/*
 * LPUtils.java
 *
 * Copyright (c) 2006 LightPole, Inc.
 * All rights reserved.
 *
 * No part of this source code may be copied, userd, or modified
 * without the express written consent of LightPole, Inc.
 *
 * Created on November 9, 2006, 3:04 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package com.rytong.tools.utils;

//#define Android2.2
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.StreamCorruptedException;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.UUID;
import java.util.Vector;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.json.JSONArray;
import org.json.JSONObject;
import org.keplerproject.luajava.LuaObject;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnDismissListener;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetFileDescriptor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Bitmap.Config;
import android.graphics.PorterDuff.Mode;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.telephony.CellLocation;
import android.telephony.TelephonyManager;
import android.telephony.cdma.CdmaCellLocation;
import android.telephony.gsm.GsmCellLocation;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.view.ViewGroup.LayoutParams;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import com.rytong.tools.R;
import com.rytong.tools.clienthello.ClientHello;
import com.rytong.tools.crypto.AESCipher;
import com.rytong.tools.crypto.HMac;
import com.rytong.tools.crypto.MD5;
import com.rytong.tools.crypto.RSACipher;
import com.rytong.tools.datastorage.PackageManagerAndroid;
import com.rytong.tools.httpconnect.HttpManager;
import com.rytong.tools.httpconnect.WaitDialog;
import com.rytong.tools.httpconnect.WaitDialog.Task;
import com.rytong.tools.offstore.OffStoreDB;
import com.rytong.tools.offstore.OffStoreDownload;
import com.rytong.tools.ui.BaseView;
import com.rytong.tools.ui.Component;
import com.rytong.tools.ui.LPCheckBox;
import com.rytong.tools.ui.LPKeyBoard;
import com.rytong.tools.ui.LPLayout;
import com.rytong.tools.ui.LPLayout.MyLPLayout;
import com.rytong.tools.ui.LPRadio;
import com.rytong.tools.ui.LPScrollView;
import com.rytong.tools.ui.LPSelect;
import com.rytong.tools.ui.LPSelectOption;

/**
 * Utility class.
 */
public final class Utils {
	//保存校徽的地址
	public static String SCHOOL_IMAGE_PATH = null;

    private static int BRHEIGHT;
    private static Activity activity_;
    // 是否打印标志
    private static boolean isPrintMessage_;
    // 字体缩放参数，如果手机分辨率和密度同比增长，则该参数�，表示不需缩放，如果不匹配，则需校正该参数设�?
    public static float SCALEDFONT;
    // 基准屏幕的宽,该值应和服务端??�义xml的基准�??幕保?��?��?��?
    public static int BenchmarkresolutionW_;
    // 基准屏幕�??��,该值应和服务端定义xml的基�?��幕保持一�?
    public static int BenchmarkresolutionH_;
    /**
     * Used for gzip. Re. rfc1951.
     */
    static int gIndex = 0;
    static int bitByte = 0;
	static int bitIndex = 0;
	private final static int MAX_BITS = 16;
	private final static int[] EXTRA_L_BITS = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };
	private final static int[] EXTRA_L_VALUES = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115,
			131, 163, 195, 227, 258 };
	private final static int[] EXTRA_D_BITS = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12,
			13, 13 };
	private final static int[] EXTRA_D_VALUES = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025,
			1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 };
	private final static int[] DYNAMIC_L_ORDER = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };

    // 界面X方向参考缩放参�此参数为控件宽?��者字体大小的参考�?
    public static float SCALEDATEX;
    // 界面Y方向参考缩放参�此参数为控件高的参考�?
    public static float SCALEDATEY;
    /** Default alpha value used to draw menu panels and status bars. */
    public final static int DEFAULT_TRANSPARENCY = 0xa0000000;
    final static int OK_KEY = -5;
    final static int LEFT_SOFTKEY = -6;
    final static int RIGHT_SOFTKEY = -7;

    // if it is sony ericsson, SONY_ERICSSON is true.
    public final static boolean SONY_ERICSSON = false;
    // 日志名称
    public static final String LOGNAME = "LPC";
    /**
     * Used as indices in text parser's return result of a line break in a string.
     */
    public final static int LBI_BREAK = 0; // Break position (this char is in current
    // line)
    public final static int LBI_NEXT = 1; // Next char position to resume scanning (to
    // skip tags)
    public final static int LBI_TYPE = 2; // Line break type: newline, paragraph, ...,
    // defined below.
    public final static int LBI_START = 3; // Starting position of this line.
    public final static int LBI_SIZE = 4; // Number of linebreak indices.

    /**
     * Types of line breaks.
     */
    final static int LB_NEWLINE = 0;
    final static int LB_PARAGRAPH = 1;
    final static int LB_SKIP = 2; // Skip characters within [LBI_BREAK,
    // LBI_NEXT)
    final static int LB_HYPHEN = 3;

    /**
     * The number of alpha transparency levels。will be reset by numAlphaLevels() in LPMid.java. The minimum
     * numAlphaLevel_ is 2, which indicates only support for full transparency and full opacity.
     */
    final static int numAlphaLevel_ = 256;

    final static int BLUE = 0xFF0000FF;
    final static int WHITE = 0xFFFFFFFF;
    final static int BLACK = 0xFF000000;
    final static int GREY = 0xFF808080;
    final static int SELECTED_LINK_COLOR = 0xFF808080;
    public final static int TABBARBACKGROUNDCOLOR = 0xFF294B78;

    public final static char MATCH = '\"';

    /** True if the user selects item Map */
    public static boolean toMapView_;

    final static String SPLIT_CHARACTERS = " ,.";

    // 调用系统相机的请求码
    public final static int CAMERA_REQUEST_CODE = 1001;

    // 解读并存储assets文件夹下的Config.txt文件信息
    private static HashMap<String, String> configHm_;

    // 连点事件?��时间间隔
    public static int jat_lag = 0;
    
    // tr换背景色时候用到的颜色。
    public static final String TR_CHANGE_BG_ = "#FF7896D6";
    
    // 页面上的滚动视图。
    public static LPScrollView sc_ = null;
    
    // 用于存储界面手机自带键的LuaObject。
    public static HashMap<String, LuaObject> keyHash_ = null;
    
    // 模拟的同步请求的请求个数。
    public static int SYN_REQUEST_NUMBER_ = 0;
    
    // 模拟同步提交表单的请求个数。
    public static int SYN_SUBMIT_REQUEST_NUMBER_ = 0;
    
    public static InputMethodUtil immUtils = null;
    /**
     * 密码键盘弹出dialog
     */
    public static Dialog keyDlg_ = null;
    //图片下载器
    public static AsyncImageLoader imageLoader_ = null;
    
    /**-----------------------------SIT\UAT\TRL服务器地址------------------------------**/
    //校徽uat/sit/trl地址
	//public static String SCHOOL_BADGE = "http://182.119.171.72:8992/mobilebank/college/";
    //校徽生产地址
	public static String SCHOOL_BADGE = "http://wap.95559.com.cn/mobilebank/images/college/";
	
    //UAT/SIT/TRL证书
    public static String CERTIFICATE = "root_u.png";
    //生产证书
//    public static String CERTIFICATE = "root_p.png";
    
    //生产地址
//    public static String SERVER_URI = "http://mbank.95559.com.cn:8083";        
//    public static String SERVER_URI_NO_PORT = "http://mbank.95559.com.cn";
    
	// SIT内网
//    public static String SERVER_URI = "http://182.119.166.208:80";
//    public static String SERVER_URI_NO_PORT = "http://182.119.166.208";
// 
	// SIT外网
// 	public static String SERVER_URI = "http://124.74.249.19:8913";
// 	public static String SERVER_URI_NO_PORT = "http://124.74.249.19";
//
//  UAT内网
//    public static String SERVER_URI = "http://182.119.166.209:80";
//    public static String SERVER_URI_NO_PORT = "http://182.119.166.209";

 // UAT外网
    public static String SERVER_URI = "http://124.74.249.19:8914";
	public static String SERVER_URI_NO_PORT = "http://124.74.249.19";

 // TRL内网
 // public static String SERVER_URI = "http://182.119.166.210:80";
 // public static String SERVER_URI_NO_PORT = "http://182.119.166.210";

 // TRL外网
 // public static String SERVER_URI = "http://124.74.249.19:8915";
 // public static String SERVER_URI_NO_PORT = "http://124.74.249.19";
 /**---------------------------------------------------------------------**/
    
//	public static String SERVER_URI = "http://192.168.241.3:7002";
//	public static String SERVER_URI_NO_PORT = "http://192.168.241.3";
    
    /**
     * @return
     */
    public final static byte[] getClientGMTUnixTime() {
        // get local time.4 bytes.
        Calendar cal = Calendar.getInstance();
        Date date = cal.getTime();
        int hours = date.getHours();
        byte[] clientGmtUnixTime = new byte[4];
        clientGmtUnixTime[0] = (byte) ((hours & 0x0000FF00) >> 8);
        clientGmtUnixTime[1] = (byte) ((hours & 0x000000FF));
        int minutes = date.getMinutes();
        clientGmtUnixTime[2] = (byte) ((minutes & 0x0000FF00) >> 8);
        clientGmtUnixTime[3] = (byte) ((minutes & 0x000000FF));
        return clientGmtUnixTime;
    }

    /**
     * 实例化图片下载器
     */
    public static AsyncImageLoader getAsyncImageLoader(){
    	if(null == imageLoader_){
    		imageLoader_ = new AsyncImageLoader();
    	}
    	return imageLoader_;
    }
    /**
     * 发送端�?
     * 
     * @param phoneNum
     * @param content
     */
    public final static String sendSms(String phoneNum, String content) {
    	String errorCode = "0";
    	//短信内容为空
    	if(TextUtils.isEmpty(content)){
    	    errorCode = "1";
    	    return errorCode;
    	}
    	//手机号为空
    	if(TextUtils.isEmpty(phoneNum)){
    	    errorCode = "2";
    	    return errorCode;
    	}
    	//手机号码不为11位
    	if(phoneNum.length() != 11){
    	    errorCode = "3";
    	    return errorCode;
    	}
    	
    	// 发送短信
        Intent intent = new Intent();
        // 系统默认的action，用来打开默认的短信界�?
        intent.setAction(Intent.ACTION_SENDTO);
        // 需要发短息的号�?
        intent.setData(Uri.parse("smsto:" + phoneNum));
        intent.putExtra("sms_body", content);
        activity_.startActivity(intent);
        return errorCode;
    }

    /**
     * 判断网络是否可用
     * @return
     */
    public static boolean isConnectByNet(){
    	ConnectivityManager conn = (ConnectivityManager)activity_.getSystemService(Context.CONNECTIVITY_SERVICE);
    	NetworkInfo netInfo = conn.getActiveNetworkInfo();	
    	if (null == netInfo || !netInfo.isAvailable()) {
    		return false;
    	}
    	return true;
    }

    /**
     * 清空界面所有控件
     */
    public static void clearWidget() {
        // TODO Auto-generated method stub
        if (null != Component.VWIDGETARRAY && !Component.VWIDGETARRAY.isEmpty()) {
            int size = Component.VWIDGETARRAY.size();
            Component comp;
            int index = Integer.MIN_VALUE;
            for (int i = 0; i < size; i++) {
                comp = (Component) Component.VWIDGETARRAY.get(i);
                if (null != comp.getTag() && comp.getTag().equalsIgnoreCase("body")) {
                    index = i;
                    break;
                }
            }
            if (index != Integer.MIN_VALUE) {
                comp = (Component) Component.VWIDGETARRAY.get(index);
				if(null != comp){
					comp.releaseResource(comp);
				}
            }
        }
    }

	/**
	*获取保存学校的id
	*/
	public static String getUniversityID(){
		String id = null;
		String saveUniversity = PackageManagerAndroid.ANDROIDDB.get("university_select");
		if(null != saveUniversity && !"".equalsIgnoreCase(saveUniversity)){
			String[] university =  saveUniversity.split("\\|");
			id = university[1];
		}
		return id;
	}
	
    /**
     * 获取资源图片
     * 
     * @param context
     * @param resourcesName
     * @return
     */
    public final static Bitmap getBitmapFromResources(Context context, String resourcesName) {
        Bitmap bitmap = null;
        byte[] buffer = null;
        if (resourcesName == null)
            return bitmap;

        //针对大学生版本时取图片
        if(resourcesName.equalsIgnoreCase("bj.png")){
        	String version = PackageManagerAndroid.ANDROIDDB.get("version");
    		if(null != version && version.equalsIgnoreCase("university")){
    			buffer = Utils.readFile(SCHOOL_IMAGE_PATH+getUniversityID()+".png");
    			if(null != buffer){
    				 bitmap = BitmapFactory.decodeByteArray(buffer, 0, buffer.length);
    				 buffer = null;
    				 return bitmap;
    			}
    		}
        }
        
		Object img = null;
		// 先补png后缀名。
		resourcesName = getPNGName(resourcesName);
		
		if(resourcesName.startsWith("local")){
			 resourcesName = resourcesName.substring(resourcesName.indexOf("local:") + 6).trim();
		}
		 
		// 插件资源。
		img = OffStoreDB.PLUGDB.find(resourcesName);
		if (img != null) {
			buffer = Utils.readFile(OffStoreDownload.FILEROOT.concat(OffStoreDownload.PLUGROOT).concat(resourcesName));
			if (buffer != null) {
				bitmap = getBitmap(buffer);
			}
		}
		 
		// 离线资源
		if (bitmap == null) {
		//  img = OffStoreDB.OFFLINEDB.find(resourcesName);
		    String basePath = Utils.getFilePath(new File(OffStoreDownload.FILEROOT.concat(OffStoreDownload.OFFLINEROOT))
		    , resourcesName);
		    if (basePath != null) {
		        if(!basePath.endsWith("/")){
		            basePath += "/";
		        }
		        buffer = Utils.readFile(basePath.concat(resourcesName));
		        if (buffer != null) {
		            bitmap = BitmapFactory.decodeByteArray(buffer, 0, buffer.length);
		        }
		    }
		}
		
		// file：write写出的资源
		if (bitmap == null) {
		    buffer = Utils.readFile(OffStoreDownload.FILEROOT.concat(OffStoreDownload.WRITEROOT).concat(resourcesName));
		    if (buffer != null) {
		        bitmap = BitmapFactory.decodeByteArray(buffer, 0, buffer.length);
		    }
		}
		// 资源文件
		if (bitmap == null) {
		    // 如果sql中没有存储对应的图片，则将后缀去掉，在资源文件里面搜索
		    if (resourcesName.endsWith(".png")) {
		        resourcesName = resourcesName.substring(0, resourcesName.lastIndexOf(".png"));
		    }
		    resourcesName = resourcesName.toLowerCase();
		    int resourcesId = getResourcesId(context, resourcesName, "drawable");
		    if (resourcesId != 0) {
		        bitmap = getBitmap(resourcesId, (Activity) context);
		    }
		}

        return bitmap;
    }
	
	/**
	 * 下载图片
	 * @param imageUrl
	 * @return
	 * @throws Exception
	 */
	public static BitmapDrawable getBitmapByDownload(String imageUrl) throws Exception{
		BitmapDrawable bitmap = null;
		URL url = new URL(imageUrl);
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		conn.setConnectTimeout(80);
		InputStream is = conn.getInputStream();
		bitmap = new BitmapDrawable(is); // 创建图片
		conn.disconnect();
		return bitmap;
	}
	
    /**
     * 获取本地文件
     * 
     * @param name
     * @return
     * */
    public static String getFileFromOffline(String fileName){
    	String result = null;
		
    	//得到当前文件的路径
    	//String fPath = String.valueOf(OffStoreDB.OFFLINEDB.findImage(fileName));
    	String fPath = OffStoreDB.readOffline(OffStoreDB.OFFLINEDB, fileName);
    	if(null == fPath){
    		fPath = OffStoreDB.readOffline(OffStoreDB.PLUGDB, fileName);
    	}
    	if(null != fPath){
    		byte[] buffer = null;
    		String path = String.valueOf(fPath);
    		try {
    			buffer = Utils.readFile(OffStoreDownload.FILEROOT.concat(OffStoreDownload.PLUGROOT).concat(path));
    			if (null == buffer){
    				buffer = Utils.readFile(OffStoreDownload.FILEROOT.concat(OffStoreDownload.OFFLINEROOT).concat(path));            	
    			}
    			if (null == buffer) {
    				buffer = Utils.readFile(OffStoreDownload.FILEROOT.concat(OffStoreDownload.WRITEROOT).concat(path));
    			}
    		}catch(Exception e){
    			e.printStackTrace();
    		}
    		if (null != buffer){
    			try {
    				result = new String(buffer, "UTF-8");
    			} catch (UnsupportedEncodingException e) {
    				// TODO Auto-generated catch block
    				Utils.printException(e);
    			}        	
    		}
    	}
        return result;
    }
    
    /**
     * 将byte转换成图片
     */
	public static Bitmap getBitmap(byte[] data) {
		// TODO Auto-generated method stub
		if(data != null && data.length > 0){
    	    BitmapFactory.Options opt = new BitmapFactory.Options();
    	    opt.inPreferredConfig = Bitmap.Config.RGB_565;
    	    opt.inPurgeable = true;
    	    opt.inInputShareable = true;
    	        
    	    Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length , opt);
    	    return bitmap;
    	} 
    	return null;
	}
	
	/**
	 * 读取字节流
	 * */
    public static byte[] readStream(InputStream inStream) throws Exception{
    	ByteArrayOutputStream outstream = new ByteArrayOutputStream();
    	byte[] buffer = new byte[1024];
    	int len = -1;
    	while((len = inStream.read(buffer)) != -1){
    		outstream.write(buffer, 0, len);
    	}
    	outstream.close();
    	inStream.close();
    	return outstream.toByteArray();
    }
    
	/**
	 * 计算缩放系数
	 * */
    private static int computeSampleSize(BitmapFactory.Options options,
            int minSideLength, int maxNumOfPixels) {
        int initialSize = computeInitialSampleSize(options, minSideLength,maxNumOfPixels);

        int roundedSize;
        if (initialSize <= 8 ) {
            roundedSize = 1;
            while (roundedSize < initialSize) {
                roundedSize <<= 1;
            }
        } else {
            roundedSize = (initialSize + 7) / 8 * 8;
        }

        return roundedSize;
    }

    //计算一个缩放参数
    private static int computeInitialSampleSize(BitmapFactory.Options options,int minSideLength, int maxNumOfPixels) {
        double w = options.outWidth;
        double h = options.outHeight;

        int lowerBound = (maxNumOfPixels == -1) ? 1 :
                (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
        int upperBound = (minSideLength == -1) ? 128 :
                (int) Math.min(Math.floor(w / minSideLength),
                Math.floor(h / minSideLength));

        if (upperBound < lowerBound) {
            // return the larger one when there is no overlapping zone.
            return lowerBound;
        }

        if ((maxNumOfPixels == -1) &&
                (minSideLength == -1)) {
            return 1;
        } else if (minSideLength == -1) {
            return lowerBound;
        } else {
            return upperBound;
        }
    }
    /**
     * 获取资源id
     * 
     * @param context
     * @param resourcesName
     * @param resourcesType
     * @param packageName
     * @return
     */
    public final static int getResourcesId(Context context, String resourcesName, String resourcesType) {
        int resourcesId = 0;
        resourcesId = context.getResources().getIdentifier(resourcesName, resourcesType, context.getPackageName());
        return resourcesId;
    }

    /**
     * 获取项目Config中的app名称，用于联网后台区别报�?
     * 
     * @param activity
     */
    public final static void getAppName(Activity activity) {
        HttpManager.APPNAME = getConfigStringFormAsset(activity, "app");
    }

    public final static void getPlatform(Activity activity) {
        HttpManager.OPLATFORM = getConfigStringFormAsset(activity, "oPlatform");
    }

    public final static String getClientType(Activity activity) {
        return getConfigStringFormAsset(activity, "clientType");
    }

    /**
     * 判断字符串是否以.png结尾,如果不是加上该后缀
     */
    public final static String getPNGName(String name) {
        name = name.trim();
        if (!name.endsWith(".png")) {
            if (name.indexOf(".") != -1)
                name = name.substring(0, name.indexOf("."));
            name = name.concat(".png");
        }
        return name;
    }

    public final static Bitmap getBitmap(int rdoing, Activity bv) {
        // TODO Auto-generated method stub
        BitmapFactory.Options opt = new BitmapFactory.Options();
        opt.inPreferredConfig = Bitmap.Config.RGB_565;
        opt.inPurgeable = true;
        opt.inInputShareable = true;
        InputStream is = bv.getResources().openRawResource(rdoing);

        Bitmap img = BitmapFactory.decodeStream(is, null, opt);
        try {
            is.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            Utils.printException(e);
        }
        return img;
    }
    

	/**
     * 添加倒影，原理，先翻转图片，由上到下放大透明度
     * 
     * @param originalImage
     * @return
     */
    public static Bitmap createReflectedImage(Bitmap originalImage) {
        // The gap we want between the reflection and the original image
        final int reflectionGap = 1;

        int width = originalImage.getWidth();
        int height = originalImage.getHeight();

        // This will not scale but will flip on the Y axis
        Matrix matrix = new Matrix();
        matrix.preScale(1, -1);
        
        // Create a Bitmap with the flip matrix applied to it.
        // We only want the bottom half of the image
        Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0,
                height * 5 / 8, width, height * 3 / 8, matrix, false);
//        Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0,
//        		height / 5, width, height / 5, matrix, false);

        // Create a new bitmap with same width but taller to fit reflection
        Bitmap bitmapWithReflection = Bitmap.createBitmap(width,
                (height + height * 3 / 8), Config.ARGB_8888);
//        Bitmap bitmapWithReflection = Bitmap.createBitmap(width,
//        		(height + height / 5 + reflectionGap), Config.ARGB_8888);

        // Create a new Canvas with the bitmap that's big enough for
        // the image plus gap plus reflection
        Canvas canvas = new Canvas(bitmapWithReflection);
        // Draw in the original image
        canvas.drawBitmap(originalImage, 0, 0, null);
        // Draw in the gap
        Paint defaultPaint = new Paint();
        defaultPaint.setColor(Color.TRANSPARENT);
        canvas.drawRect(0, height, width, height + reflectionGap, defaultPaint);
        // Draw in the reflection
        canvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null);

        // Create a shader that is a linear gradient that covers the reflection
        Paint paint = new Paint();
        LinearGradient shader = new LinearGradient(0,
                originalImage.getHeight(), 0, bitmapWithReflection.getHeight()
                        + reflectionGap, 0x70ffffff, 0x00ffffff, TileMode.CLAMP);
        // Set the paint to use this shader (linear gradient)
        paint.setShader(shader);
        // Set the Transfer mode to be porter duff and destination in
        paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
        // Draw a rectangle using the paint with our linear gradient
        canvas.drawRect(0, height, width, bitmapWithReflection.getHeight()
                + reflectionGap, paint);
        
        return bitmapWithReflection;
    }
    
    /**
     * 圆角图片处理
     * @param bitmap
     * @param context
     * @return
     */
    public static Bitmap toRoundCorner(Bitmap bitmap,Context context) {
        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
                        bitmap.getHeight(), Config.ARGB_8888);
        Canvas canvas = new Canvas(output);
        final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
        Drawable centerDrawable = context.getResources().getDrawable(R.drawable.gallery_round_bg);
        centerDrawable.setBounds(rect);
        centerDrawable.draw(canvas);
        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);
        return output;
    }
    
    public final static int getColorValue(String value) {
        String colorstr = "";
        try {
            colorstr = getValidColorString(value);

            if (colorstr.length() > 6) {
                int color = Integer.parseInt(colorstr, 16);
                color |= 0x00000000;
                return color;
            } else {
                int color = Integer.parseInt(colorstr, 16);
                color |= 0xFF000000;
                return color;
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            Utils.printException(e);
            return 0xFFFFFFFF;
        }

    }

    /**
     * The valid color string is a 6 bit hex number. e.g., FFFFFF.
     * 
     * @param srcColorstr
     * @return
     */
    public final static String getValidColorString(final String srcColorstr) throws Exception {
        String colorstr = srcColorstr;
        if (colorstr.startsWith("#")) {
            colorstr = colorstr.substring(1);
        }
        return colorstr;
    }

    // 将字符串数组中的内�?�转换成�?���??�方便字符数组检�?
    public final static String getArrayString(String[] sa) {
        if (null == sa)
            return "";
        return Arrays.toString(sa);
    }

    final static boolean isLeftSoftKey(int key) {
        return (key == LEFT_SOFTKEY);
    }

    final static boolean isRightSoftKey(int key) {
        // Motorola some phones's right key is -22, and other is 22.
        // return (key == RIGHT_SOFTKEY || key == -RIGHT_SOFTKEY);
        return (key == RIGHT_SOFTKEY);
    }

    final static int getLeftSoftKey() {
        return LEFT_SOFTKEY;
    }

    final static int getRightSoftKey() {
        return RIGHT_SOFTKEY;
    }

    /**
     * 
     * 把字节数组保存为一个文�?
     * 
     */
    public final static File getFileFromBytes(byte[] b, String outputFile) {

        String pathString = activity_.getFilesDir().getPath().concat("/");
        BufferedOutputStream stream = null;

        File file = null;
        try {

            file = new File(pathString.concat(outputFile));
            file.createNewFile();
            FileOutputStream fstream = new FileOutputStream(file);

            stream = new BufferedOutputStream(fstream);

            stream.write(b);

        } catch (Exception e) {

            printException(e);

        } finally {
            if (stream != null) {
                try {
                    stream.close();
                } catch (IOException e1) {
                    printException(e1);
                }
            }
        }
        return file;

    }

    /**
     * 根据文件后缀名返回文件类�?
     * 
     * @param fileTemp
     * @return
     */
    public final static String getMIMEType(File fileTemp) {
        // TODO Auto-generated method stub
        String type = "";
        String fName = fileTemp.getName();
        String end = fName.substring(fName.lastIndexOf(".") + 1, fName.length()).toLowerCase();
        if (end.equals("m4a") || end.equals("mp3") || end.equals("mid") || end.equals("xmf") || end.equals("ogg")
                || end.equals("wav")) {
            type = "audio";
        } else if (end.equals("3gp") || end.equals("mp4")) {
            type = "video";
        } else if (end.equals("jpg") || end.equals("gif") || end.equals("png") || end.equals("jpeg")
                || end.equals("bmp")) {
            type = "image";
        } else if (end.equals("apk")) {
            type = "application/vnd.android.package-archive";
        } else if (end.equals("zip")) {
            type = "zip";
        } else if (end.equals("apk")) {

        } else {
            type += "/*";
        }
        return type;
    }

    /**
     * Graphics.drawRegion() has a bug in 4.2.1 and we have to use a replacement function.
     */
    public final static void drawRegion(Canvas g, Bitmap img, int srcX, int srcY, int width, int height, int dstX,
            int dstY) {
        g.drawBitmap(img, new Rect(srcX, srcY, srcX + width, srcY + height), new Rect(dstX, dstY, dstX + width, dstY
                + height), new Paint());
    }

    public final static int fixTransparentPixel(int pixel) {
        // We don't use semitransparent pixel if the phone only support for full
        // transparency and full opacity.
        if (numAlphaLevel_ > 2 && (pixel & 0xff000000) != 0)
            return (pixel & 0x00ffffff) + DEFAULT_TRANSPARENCY;
        else
            return pixel;
    }

    /**
     * Given an image, assign transparency value to its non-background pixels (background pixels are pixels that are
     * completely transparent).
     * 
     * @param transparency
     *            255 == totally opaque.
     */
    public final static Bitmap fixTransparentImage(Bitmap img) throws Exception {
        if (null == img)
            return null;
        int width = img.getWidth();
        int height = img.getHeight();
        int sz = width * height;
        int[] rgb = new int[sz];
        // Params: (rgb, offset, scanlength, x, y, width, height)
        // rgbData[offset + (a - x) + (b - y) * scanlength] = P(a, b);
        img.getPixels(rgb, 0, width, 0, 0, width, height);
        for (int i = 0; i < sz; ++i) {
            rgb[i] = fixTransparentPixel(rgb[i]);
        }
        img = Bitmap.createBitmap(rgb, width, height, Bitmap.Config.RGB_565);
        return img;
    }

    /*
     * Check if the image is over 4kB or not.
     * 
     * @param name the full name with a path of an image file.
     * 
     * @return
     */
    // private final final static final boolean isImgBelow4KB(String name) {
    // boolean isNotOver = ConfigManager.IMAGE_TRANSPARENCY;
    // try {
    // int imgSize = 0;
    // InputStream is = null;
    // is = new Object().getClass().getResourceAsStream(name);
    // imgSize = is.available();
    // if (imgSize < 1024 * 4){
    // isNotOver = true;
    // }
    // } catch (Exception e) {
    // printOutToConsole("LPUtils.isImgOver4KB(): " + e.toString());
    // }
    // return isNotOver;
    // }

    public final static String abbrevString(String title, Paint font, int maxWidth) {
        if (title == null)
            return "";
        if (font.measureText(title) > maxWidth) {
            int pos = nextLinePosition(title.toCharArray(), 0, font, maxWidth,
                    font.getTextWidths(ELLIPSIS, 0, ELLIPSIS.length, new float[ELLIPSIS.length]));
            if (pos == -1)
                return title;
            else
                return title.substring(0, pos) + "...";
        } else
            return title;
    }

    final static String appendDots(String src, Paint font, int maxWidth) {
        if (src == null || font == null || maxWidth < 0) {
            return null;
        }
        String dest = null;
        dest = src + "...";
        while (font.measureText(dest) > maxWidth) {
            dest = src.substring(0, src.length() - 2) + "...";
        }
        return dest;
    }

    private final static char ELLIPSIS[] = { '.', '.', '.' };

    public final static int getEllipsisWidth(Paint f) {
        return f.getTextWidths(ELLIPSIS, 0, ELLIPSIS.length, new float[ELLIPSIS.length]);
    }

    /**
     * Is this character whitespace?
     */
    public final static boolean isWhitespace(char ch) {
        return (ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t');
    }

    /**
     * Case insensitive string match
     * 
     * @param ignoreCase
     *            if true, ignore case
     * @param s1
     * @param s2
     */
    public final static boolean stringMatch(boolean ignoreCase, String s1, String s2) {
        int cmplen = Math.max(s1.length(), s2.length());
        if ((s1 == null) || (s2 == null)) {
            return false;
        }
        return s1.regionMatches(true, 0, s2, 0, cmplen);
    }

    /**
     * Given a starting position in a string, return the next position that this string should be split if it cannot fit
     * within the given width. If it does not fit, we will include an ellipsis at the end to indicate broken line. If it
     * does fit, we return -1.
     */
    public final static int nextLinePosition(char[] str, int pos, Paint f, int maxWidth, int ellWidth) {
        int strWidth = 0;
        while (pos < str.length) {
            if (str[pos] == '\n') {
                return pos;
            }
            strWidth += f.measureText(String.valueOf(str[pos]));
            if (strWidth + ellWidth > maxWidth) {
                // If the rest of string can fit instead of the ellipsis, put it
                // there.
                // int tmp = f.getTextWidths(str, pos + 1, str.length - pos - 1,
                // new float[str.length - pos - 1]);
                int tmp = (int) f.measureText(str, pos + 1, str.length - pos - 1);
                if (strWidth + tmp <= maxWidth) {
                    return -1;
                } else {
                    return pos;
                }
            }
            ++pos;
        }
        return -1;
    }

    /**
     * Starting from pos in str, find the longest string that fits in maxLineWidth. If doesn't fit, break the line by
     * hyphenation or at a line break point.
     * 
     * If newLine is true, we are starting from a new line and should get rid of initial white spaces.
     * 
     * Returns the position of the next character to be scanned in str after this line break.
     */
    public final static int nextLineLayout(char[] str, int pos, Paint f, int maxLineWidth, int hyphenWidth,
            int[] linebreak, boolean newLine) {
        int strWidth = 0;
        int startPos = pos;
        int lastBreakPoint = pos;

        // Filter out initial white spaces at start of a line.
        if (newLine) {
            while (pos < str.length && (str[pos] == ' ' || str[pos] == '\t'))
                ++pos;
        }

        linebreak[LBI_START] = pos;
        while (pos < str.length) {
            boolean punct = false;
            switch (str[pos]) {
            // NOTE: don't recognize CR because in XML, only <br> or <p> should
            // matter.
            case '\n':
                // Insert a newline.
                linebreak[LBI_BREAK] = pos - 1;
                linebreak[LBI_NEXT] = pos + 1;
                linebreak[LBI_TYPE] = LB_SKIP;
                return pos + 1;
            case '<': {
                // Look ahead to see if we have a <p>, <br>, <p/>, <br/>, </p>,
                // </br>, <b> <tr> <td>
                // XXX We ignore complex cases, such as newlines are inserted
                // into tags.
                // NOTE: the 32 limit is an arbitrary one
                int endPos = pos;
                while (endPos < (str.length - 1) && endPos - pos < 8) {
                    ++endPos;
                    if (str[endPos] == '>') {
                        int pp1 = pos + 1;
                        int pp2 = pos + 2;
                        int pp3 = pos + 3;
                        char ch_pp1 = Character.toLowerCase(str[pp1]);
                        if (ch_pp1 == 'p' && (pp2 == endPos || str[pp2] == '/' || str[pp2] == ' ')) {
                            linebreak[LBI_BREAK] = pos - 1;
                            linebreak[LBI_NEXT] = endPos + 1;
                            linebreak[LBI_TYPE] = LB_PARAGRAPH; // Paragraph
                            return endPos + 1;
                        } else if (ch_pp1 == 'b'
                                && (pp2 == endPos || (Character.toLowerCase(str[pp2]) == 'r' && (pp3 == endPos
                                        || str[pp3] == '/' || str[pp3] == ' ')))) {
                            linebreak[LBI_BREAK] = pos - 1;
                            linebreak[LBI_NEXT] = endPos + 1;
                            // Only add newline if this is a br.
                            linebreak[LBI_TYPE] = (pp2 == endPos) ? LB_SKIP : LB_NEWLINE;
                            return endPos + 1;
                        } else if (ch_pp1 == '/' || ch_pp1 == 'i' || ch_pp1 == 'e' || ch_pp1 == 's' || ch_pp1 == 'c'
                                || ch_pp1 == 't' || ch_pp1 == 'h') {

                            // Ignore <em>, <strong>, <center>
                            // Ignore all kinds of end tags.
                            linebreak[LBI_BREAK] = pos - 1;
                            linebreak[LBI_NEXT] = endPos + 1;
                            linebreak[LBI_TYPE] = LB_SKIP;
                            return endPos + 1;
                        }
                    }
                }
                // XXX FIXME: Ignore <a href=...> and <font ...>, <a target...>,
                // <a title...>, <a rel...> here. We will capture the hyper link
                // and tie it to the link body later.
                char ch_pp1 = Character.toLowerCase(str[pos + 1]);
                if (str.length - pos >= 5 && (ch_pp1 == 'a' || ch_pp1 == 'f')) {
                    if (ch_pp1 == 'a') {
                        // Skip spaces between a and href
                        endPos = pos + 2;
                        while (endPos < str.length && str[endPos] == ' ')
                            ++endPos;
                    } else {
                        endPos = pos + 1;
                    }
                    if (str.length - endPos > 3) {
                        ch_pp1 = Character.toLowerCase(str[endPos]);
                        char ch_pp2 = Character.toLowerCase(str[endPos + 1]);
                        char ch_pp3 = Character.toLowerCase(str[endPos + 2]);
                        char ch_pp4 = Character.toLowerCase(str[endPos + 3]);
                        if ((ch_pp1 == 'h' && ch_pp2 == 'r' && ch_pp3 == 'e' && ch_pp4 == 'f')
                                || (ch_pp1 == 'f' && ch_pp2 == 'o' && ch_pp3 == 'n' && ch_pp4 == 't')
                                || (ch_pp1 == 't' && ch_pp2 == 'a' && ch_pp3 == 'r' && ch_pp4 == 'g')
                                || (ch_pp1 == 't' && ch_pp2 == 'i' && ch_pp3 == 't' && ch_pp4 == 'l')
                                || (ch_pp1 == 'r' && ch_pp2 == 'e' && ch_pp3 == 'l')) {
                            // Ignore everything, including newline, till next
                            // '>'
                            while (endPos < str.length && str[endPos] != '>')
                                ++endPos;
                        }
                    }
                    linebreak[LBI_BREAK] = pos - 1;
                    if (endPos + 1 < str.length)
                        linebreak[LBI_NEXT] = endPos + 1;
                    else
                        linebreak[LBI_NEXT] = str.length - 1;
                    linebreak[LBI_TYPE] = LB_SKIP;
                    return endPos + 1;
                }
                // XXX FIXME: Ignore <p class=...> & <img src=...>,<span ...>
                // <lp...> , </lp:...>, <table > <div>here. We will capture the
                // hyper link
                // and tie it to the link body later.
                if (str.length - pos >= 8
                        && (ch_pp1 == 'p' || ch_pp1 == 'i' || ch_pp1 == 'l' || ch_pp1 == 's' || ch_pp1 == 't' || ch_pp1 == 'd')
                        || ch_pp1 == '/') {
                    endPos = pos + 2;
                    // Ignore everything, including newline, till next '>'
                    while (endPos < str.length && str[endPos] != '>')
                        ++endPos;

                    linebreak[LBI_BREAK] = pos - 1;
                    linebreak[LBI_NEXT] = endPos + 1;
                    linebreak[LBI_TYPE] = LB_SKIP;
                    return endPos + 1;
                }

                // For tags that we do not recognize, fall through.
            }
            case ' ':
            case '\t':
                lastBreakPoint = pos;
                // fall through
            default:
                // Check one more character to see if it fits current string. If
                // not,
                // try to break at the last line break point. If that is too far
                // away,
                // add a hyphen at this place.
                strWidth += f.measureText(String.valueOf(str[pos]));
                if (strWidth >= maxLineWidth) {
                    // This was meant for hyphenation. When we insert a newline,
                    // can do that right at the starting point.
                    if (lastBreakPoint == startPos) {
                        lastBreakPoint = (pos == startPos) ? pos : (pos - 1);
                    }
                    linebreak[LBI_BREAK] = lastBreakPoint - 1;
                    linebreak[LBI_NEXT] = lastBreakPoint;
                    linebreak[LBI_TYPE] = LB_NEWLINE;
                    return lastBreakPoint;
                }
            }
            ++pos;
        }
        return -1;
    }

    /**
     * Starting from pos in str, find the longest string that fits in maxLineWidth.
     * 
     * Don't need to check
     * <p>
     * , <br>
     * ,
     * <p/>
     * , <br/>
     * ,
     * </p>
     * , </br>, <b>
     * <tr>
     * <td>again. They should be parsed by HTML.
     */
    public final static int getLineEndIndex(char[] chars, int pos, Paint f, int LineWidth, int[] linebreak,
            boolean newLine, boolean isTrimHeadBlank, boolean isBreakWord) {
        if (chars == null || f == null)
            return -1;
        int strWidth = 0;
        int startPos = pos;
        int lastBreakPoint = pos;
        // Filter out initial white spaces at start of a line.
        if (newLine) {
            if (isTrimHeadBlank) {
                while (pos < chars.length && (chars[pos] == ' ' || chars[pos] == '\t'))
                    ++pos;
            } else {
                while (pos < chars.length && chars[pos] == '\t')
                    ++pos;
            }
        }
        linebreak[LBI_START] = pos;
        while (pos < chars.length) {
            switch (chars[pos]) {
            // NOTE: don't recognize CR because in XML, only <br> or <p> should
            // matter.
            case '\n':
                chars[pos] = ' ';
                return pos;
            case ' ':
            case '.':
            case '/':
            case '\t':
                lastBreakPoint = pos + 1;
            default:
                // Check one more character to see if it fits current string. If
                // not,
                // try to break at the last line break point.
                strWidth += f.measureText(String.valueOf(chars[pos]));
                if (strWidth > LineWidth) {
                    if (isBreakWord) {
                        return pos - 1;
                    } else {
                        // It is possible that a word's width bigger than line
                        // width.
                        if (lastBreakPoint == startPos && pos > startPos && newLine) {
                            return pos - 1;
                        } else {
                            return lastBreakPoint;
                        }
                    }
                }
            }
            ++pos;
        }
        return chars.length;
    }

    public final static boolean isPunct(char ch) {
        switch (ch) {
        case '.':
        case ',':
        case '?':
        case '!':
        case '\'':
        case '"':
        case ':':
        case ';':
        case '-':
            return true;
        }
        return false;
    }

    public final static String escapeHTML(String str) {
        if (str == null)
            return null;
        StringBuffer sb = new StringBuffer();
        int num = str.length();
        for (int i = 0; i < num; i++) {
            char ch = str.charAt(i);
            switch (ch) {
            case '<':
                sb.append("&lt;");
                break;
            case '>':
                sb.append("&gt;");
                break;
            case '&':
                sb.append("&amp;");
                break;
            case '"':
                sb.append("&quot;");
                break;
            case ' ':
                sb.append("&nbsp;");
                break;
            default:
                sb.append(ch);
                break;
            }
        }
        return sb.toString();
    }

    /**
     * Unescape a HTML string by filtering out &...; sequences, including &#<numbers>;. We do not consider the case
     * where one sequence is broken into multiple lines.
     */
    public final static String unescapeHTML(String str) {
        char[] src = str.toCharArray();
        char[] dest = new char[src.length];
        boolean foundAmber = false;
        int escapeIdx = -1;
        int dstIdx = 0;
        int j;
        int ch;

        for (int i = 0; i < src.length; i++) {
            switch (src[i]) {
            case '&':
                // we should not miss the case &aaa&.
                while (escapeIdx > 0 && escapeIdx < i) {
                    dest[dstIdx++] = src[escapeIdx++];
                }
                escapeIdx = i;
                break;
            case ';':
                if (escapeIdx >= 0) {
                    if (src[escapeIdx + 1] == '#') {
                        ch = 0;
                        for (j = escapeIdx + 2; j < i; ++j) {
                            if (src[j] < '0' || src[j] > '9') {
                                ch = -1;
                                break;
                            } else {
                                ch *= 10;
                                ch += src[j] - '0';
                            }
                        }
                    } else {
                        int pp1 = escapeIdx + 1;
                        int pp2 = escapeIdx + 2;
                        int pp3 = escapeIdx + 3;
                        int pp4 = escapeIdx + 4;
                        int pp5 = escapeIdx + 5;
                        if (src[pp1] == 'q' && src[pp2] == 'u' && src[pp3] == 'o' && src[pp4] == 't' && pp5 == i)
                            ch = '"';
                        else if (src[pp1] == 'a' && src[pp2] == 'm' && src[pp3] == 'p' && pp4 == i)
                            ch = '&';
                        else if (src[pp1] == 'l' && src[pp2] == 't' && pp3 == i)
                            ch = '<';
                        else if (src[pp1] == 'g' && src[pp2] == 't' && pp3 == i)
                            ch = '>';
                        else if (src[pp1] == 'n' && src[pp2] == 'b' && src[pp3] == 's' && src[pp4] == 'p' && pp5 == i)
                            ch = ' ';
                        else
                            ch = -1;
                        if (ch != -1) {
                            dest[dstIdx++] = (char) ch;
                            escapeIdx = -1;
                            break;
                        }
                    }
                } else
                    ch = -1;

                // Replace the Html Special Characters likes &#<numbers>.
                if (ch >= 0) {
                    switch (ch) {
                    case 123:
                        ch = '{';
                        break;
                    case 125:
                        ch = '}';
                        break;
                    case 133:
                        for (int k = 0; k < 3; k++)
                            dest[dstIdx++] = '.';
                        ch = -1;
                        break;
                    case 146:
                        ch = '\'';
                        break;
                    case 147:
                    case 148:
                        ch = '"';
                        break;
                    case 151:
                        ch = '-';
                        break;
                    default:
                        ch = ' ';
                        break;
                    }
                    if (ch != -1)
                        dest[dstIdx++] = (char) ch;
                } else {
                    // If current charactor is only a characters ";" ,
                    // not a Html Special Characters, we copy it in dest.
                    if (escapeIdx < 0)
                        dest[dstIdx++] = src[i];
                    else {
                        for (j = escapeIdx; j <= i; ++j)
                            dest[dstIdx++] = src[j];
                    }
                }
                escapeIdx = -1;
                break;
            default:
                if (escapeIdx < 0)
                    dest[dstIdx++] = src[i];
                else if (escapeIdx > 0 && ((i - escapeIdx) > 5)) {
                    for (int k = escapeIdx; k <= i; k++) {
                        dest[dstIdx++] = src[k];
                    }
                    escapeIdx = -1;
                }
                break;
            }
        }

        return String.valueOf(dest, 0, dstIdx);
    }

    /**
     * non-ASCII characters are encoded as: first using the UTF-8 algorithm to encode to a sequence of 2 or 3 bytes,
     * then each of these bytes is encoded as "%xx".
     */
    public final static String escapeURIComponent(String str) {
        printOutToConsole("escapeURIComponent  " + str);
        if (str == null)
            return null;
        StringBuffer sbuf = new StringBuffer();
        int ch;
        int len = str.length();
        for (int i = 0; i < len; i++) {
            ch = str.charAt(i);
            if ('A' <= ch && ch <= 'Z') {
                sbuf.append((char) ch);
            } else if ('a' <= ch && ch <= 'z') {
                sbuf.append((char) ch);
            } else if ('0' <= ch && ch <= '9') {
                sbuf.append((char) ch);
            } else if (ch == '-' || ch == '_' || ch == '.' || ch == '!' || ch == '~' || ch == '*' || ch == '\''
                    || ch == '(' || ch == ')') {
                sbuf.append((char) ch);
            } else if (ch < 0x0F) {
                sbuf.append('%');
                sbuf.append('0');
                sbuf.append(Integer.toHexString(ch));
            } else if (ch < 0x7F) {
                sbuf.append('%');
                sbuf.append(Integer.toHexString(ch));
            } else if (ch <= 0x07FF) { // non-ASCII characters and value <=
                // 0x7FF
                sbuf.append('%');
                sbuf.append(Integer.toHexString(0xc0 | (ch >> 6)));
                sbuf.append('%');
                sbuf.append(Integer.toHexString(0x80 | (ch & 0x3F)));
            } else { // non-ASCII characters and value <= 0xFFFF
                sbuf.append('%');
                sbuf.append(Integer.toHexString(0xe0 | (ch >> 12)));
                sbuf.append('%');
                sbuf.append(Integer.toHexString(0x80 | ((ch >> 6) & 0x3F)));
                sbuf.append('%');
                sbuf.append(Integer.toHexString(0x80 | (ch & 0x3F)));
            }
        }
        return sbuf.toString();
    }

    public final static String unescapeURIComponent(String url) {
        if (url == null)
            return null;
        StringBuffer sbuf = new StringBuffer();
        int len = url.length();
        int ch;
        int b;
        int total = 0;
        int more = -1;
        int hb;
        int lb;
        for (int i = 0; i < len; i++) {
            switch (ch = url.charAt(i)) {
            case '%':
                ch = url.charAt(++i);
                hb = (Character.isDigit((char) ch) ? ch - '0' : 10 + Character.toLowerCase((char) ch) - 'a') & 0xF;
                ch = url.charAt(++i);
                lb = (Character.isDigit((char) ch) ? ch - '0' : 10 + Character.toLowerCase((char) ch) - 'a') & 0xF;
                b = (hb << 4) | lb;
                break;
            default:
                b = ch;
            }
            // Decode byte b as UTF-8, sumb collects incomplete chars
            if ((b & 0xc0) == 0x80) {
                total = (total << 6) | (b & 0x3f);
                if (--more == 0)
                    sbuf.append((char) total);
            } else if ((b & 0x80) == 0x00) {
                sbuf.append((char) b);
            } else if ((b & 0xe0) == 0xc0) {
                total = b & 0x1f;
                more = 1;
            } else if ((b & 0xf0) == 0xe0) {
                total = b & 0x0f;
                more = 2;
            } else if ((b & 0xf8) == 0xf0) {
                total = b & 0x07;
                more = 3;
            } else if ((b & 0xfc) == 0xf8) {
                total = b & 0x03;
                more = 4;
            } else {
                total = b & 0x01;
                more = 5;
            }
        }
        return sbuf.toString();
    }

    /**
     * Convert a string of double number to an integer, assuming the number is a coordinate.
     */
    public final static int strCoordToInt(String strDouble) {
        char[] src = strDouble.toCharArray();
        StringBuffer dst = new StringBuffer();
        int digitsAfterDot = 0;
        boolean dotFound = false;
        for (int i = 0; i < src.length && digitsAfterDot < 6; i++) {
            if (src[i] != '.') {
                dst.append(src[i]);
                if (dotFound) {
                    ++digitsAfterDot;
                }
            } else {
                dotFound = true;
            }
        }
        // multiply by 1000000
        for (int i = digitsAfterDot; i < 6; i++) {
            dst.append('0');
        }
        return Integer.parseInt(dst.toString());
    }

    /**
     * Convert an integer coordinate into a float string.
     */
    public final static String intToFloatCoord(int coord) {
        StringBuffer buf = new StringBuffer();
        buf.append(coord);
        buf.insert(buf.length() - 6, '.');
        return buf.toString();
    }

    /**
     * Parse a ISO8601 date string and return it in a calendar object. Return UTC time.
     */
    public final static long parseISO8601(String text) throws Exception {
        printOutToConsole(text);

        // Example date string: 2006-11-29T15:30:00.000-08:00
        int idx = text.indexOf('T');
        if (idx == -1) {
            // Invalid date
            throw new IOException("错误的数据格式");
        }
        String date = text.substring(0, idx);
        int idx2 = text.indexOf('-', ++idx);
        String time;
        if (idx2 == -1) {
            time = text.substring(idx);
        } else {
            time = text.substring(idx, idx2);
        }

        idx = date.indexOf('-');
        int year = Integer.parseInt(date.substring(0, idx));
        idx2 = date.indexOf('-', ++idx);
        int month = Integer.parseInt(date.substring(idx, idx2));
        int day = Integer.parseInt(date.substring(++idx2));

        idx = time.indexOf(':');
        int hour = Integer.parseInt(time.substring(0, idx));
        idx2 = time.indexOf(':', ++idx);
        int min = Integer.parseInt(time.substring(idx, idx2));
        // The separater between seconds and time offset field can be 'Z' for
        // standard time,
        // or +/- for time zone offset.
        int idx3 = time.indexOf('+', ++idx2);
        String zoneString = null;
        int zoneOffset = 0; // time zone offset, in seconds
        if (idx3 == -1) {
            idx3 = time.indexOf('-', idx2);
        } else {
            zoneString = time.substring(idx3 + 1);
            zoneOffset = 1;
        }
        if (idx3 == -1) {
            idx3 = time.indexOf('Z', idx2);
        } else {
            zoneString = time.substring(idx3 + 1);
            zoneOffset = -1;
        }
        if (idx3 == -1) {
            idx3 = time.length();
        } else if (zoneString != null) {
            int idx4 = zoneString.indexOf(':', 0);
            if (idx4 != -1) {
                int zoneHour;
                int zoneMin;
                try {
                    zoneHour = Integer.parseInt(zoneString.substring(0, idx4));
                    zoneMin = Integer.parseInt(zoneString.substring(idx4 + 1));
                    zoneOffset *= zoneHour * 3600 + zoneMin * 60;
                } catch (Exception ignored) {
                    zoneOffset = 0;
                }
            }
        }
        int sec = 0;
        if (idx3 > idx2) {
            // Filter out sub-second component
            int idx4 = time.indexOf('.', idx2);
            if (idx4 != -1)
                idx3 = idx4;
            sec = Integer.parseInt(time.substring(idx2, idx3));
        }

        // Make a calendar time assuming that is UTC, then we'll make time zone
        // adjustment from UTC seconds.
        Calendar updatedDate = Calendar.getInstance();
        updatedDate.set(Calendar.YEAR, year);
        updatedDate.set(Calendar.MONTH, month - 1); // NOTE: month starts from
        // 0??
        updatedDate.set(Calendar.DAY_OF_MONTH, day); // Day start from 1??
        updatedDate.set(Calendar.HOUR_OF_DAY, hour);
        updatedDate.set(Calendar.MINUTE, min);
        updatedDate.set(Calendar.SECOND, sec);
        updatedDate.set(Calendar.MILLISECOND, 0);
        printOutToConsole("date: " + year + "-" + month + "-" + day + " " + hour + ":" + min + ":" + sec + " time "
                + updatedDate.getTime());
        printOutToConsole("timezone offset " + zoneOffset);
        return updatedDate.getTime().getTime() + zoneOffset * 1000;
    }

    /**
     * Displays a UTC time (in milliseconds) as MM/DD-HH:MM
     */
    public final static void formatTimeString(long utc, StringBuffer str) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date(utc));
        str.append(cal.get(Calendar.MONTH) + 1); // NOTE: month starts from 0
        str.append("/");
        str.append(cal.get(Calendar.DAY_OF_MONTH));
        str.append("-");
        str.append(cal.get(Calendar.HOUR_OF_DAY));
        str.append(":");
        str.append(cal.get(Calendar.MINUTE));
    }

    /**
     * Displays a UTC time in milliseconds as YYYY/MM/DD
     */
    public final static void formatDateString(long utc, StringBuffer str) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date(utc));
        str.append(cal.get(Calendar.YEAR));
        str.append("/");
        str.append(cal.get(Calendar.MONTH) + 1); // NOTE: month starts from 0
        str.append("/");
        str.append(cal.get(Calendar.DAY_OF_MONTH));
    }

    /**
     * Display a UTC time as format hh:mm am/pm
     */
    public final static void fromatTimeAmPm(long utc, StringBuffer str) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date(utc));
        int hour = cal.get(Calendar.HOUR);
        int minu = cal.get(Calendar.MINUTE);
        if (hour < 10)
            str.append("0");
        str.append(hour);
        str.append(":");
        if (minu < 10)
            str.append("0");
        str.append(minu);
        if (cal.get(Calendar.AM_PM) == 0)
            str.append(" AM");
        else
            str.append(" PM");
    }

    /**
     * Parse simple state response XMLs from server and retrieve attributes from it. Used by UserManager, PoiRepository
     * (add/remove POI), etc.
     */
    public final static String getXMLResponseAttribute(String reply, String attr, int startIndex, char matchCh) {
        int start = reply.indexOf(attr, startIndex);
        if (start < 0)
            return null;
        start += attr.length();
        int end = reply.indexOf(matchCh, start);
        if (end > start) {
            String s = reply.substring(start, end);
            return s;
        }
        return null;
    }

    /**
     * Check the email address whether is valid.
     */
    public final static boolean checkEmail(String emailAdd) {
        int length = emailAdd.length();
        int temp1 = emailAdd.indexOf("@");
        int temp2 = emailAdd.indexOf(".");

        // temp1 > 1 means in this email address contains an “@�and there is a
        // user’s name before it.
        // temp2 != -1 means in this email address contains an "."
        // (length - temp1 > 3) means after “@�contains at least one letter
        // except ��
        // (length - temp2 > 1) means "." is not the last letter
        if (temp1 > 1 && temp2 != -1 && (length - temp1 > 3) && (length - temp2 > 1)) {
            return true;
        } else
            return false;
    }

    /*
     * A Java implementation of the Secure Hash Algorithm, SHA-1, as defined in FIPS PUB 180-1 Copyright (C) Sam Ruby
     * 2004 All rights reserved
     * 
     * Based on code Copyright (C) Paul Johnston 2000 - 2002. See http://pajhome.org.uk/site/legal.html for details.
     * 
     * Converted to Java by Russell Beattie 2004 Base64 logic and inlining by Sam Ruby 2004 Bug fix correcting single
     * bit error in base64 code by John Wilson
     * 
     * BSD License
     * 
     * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
     * following conditions are met:
     * 
     * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
     * disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
     * the following disclaimer in the documentation and/or other materials provided with the distribution.
     * 
     * Neither the name of the author nor the names of its contributors may be used to endorse or promote products
     * derived from this software without specific prior written permission.
     * 
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
     * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */

    // /*
    // * Bitwise rotate a 32-bit number to the left
    // */
    // private final final static int rol(int num, int cnt) {
    // return (num << cnt) | (num >>> (32 - cnt));
    // }
    /*
     * Take a string and return the base64 representation of its SHA-1.
     */
    public final static String sha1(String str) throws Exception {

        // Convert a string to a sequence of 16-word blocks, stored as an array.
        // Append padding bits and the length, as described in the SHA1 standard

        byte[] x = str.getBytes("UTF-8");
        int[] blks = new int[(((x.length + 8) >> 6) + 1) * 16];
        int i;

        for (i = 0; i < x.length; i++) {
            blks[i >> 2] |= x[i] << (24 - (i % 4) * 8);
        }

        blks[i >> 2] |= 0x80 << (24 - (i % 4) * 8);
        blks[blks.length - 1] = x.length * 8;

        // calculate 160 bit SHA1 hash of the sequence of blocks

        int[] w = new int[80];

        int a = 1732584193;
        int b = -271733879;
        int c = -1732584194;
        int d = 271733878;
        int e = -1009589776;
        int num;

        for (i = 0; i < blks.length; i += 16) {
            int olda = a;
            int oldb = b;
            int oldc = c;
            int oldd = d;
            int olde = e;

            for (int j = 0; j < 80; j++) {
                if (j < 16) {
                    w[j] = blks[i + j];
                } else {
                    num = w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16];
                    w[j] = ((num << 1) | (num >>> (32 - 1)));
                }
                int t = ((a << 5) | (a >>> (32 - 5)))
                        + e
                        + w[j]
                        + ((j < 20) ? 1518500249 + ((b & c) | ((~b) & d)) : (j < 40) ? 1859775393 + (b ^ c ^ d)
                                : (j < 60) ? -1894007588 + ((b & c) | (b & d) | (c & d)) : -899497514 + (b ^ c ^ d));
                e = d;
                d = c;
                c = ((b << 30) | (b >>> (32 - 30))); // rol(b, 30);
                b = a;
                a = t;
            }

            a = a + olda;
            b = b + oldb;
            c = c + oldc;
            d = d + oldd;
            e = e + olde;
        }

        // Convert 160 bit hash to base64
        int[] words = { a, b, c, d, e, 0 };
        byte[] base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".getBytes();
        byte[] result = new byte[28];
        for (i = 0; i < 27; i++) {
            int start = i * 6;
            int word = start >> 5;
            int offset = start & 0x1f;

            if (offset <= 26) {
                result[i] = base64[(words[word] >> (26 - offset)) & 0x3F];
            } else if (offset == 28) {
                result[i] = base64[(((words[word] & 0x0F) << 2) | ((words[word + 1] >> 30) & 0x03)) & 0x3F];
            } else {
                result[i] = base64[(((words[word] & 0x03) << 4) | ((words[word + 1] >> 28) & 0x0F)) & 0x3F];
            }
        }
        result[27] = '=';

        return new String(result);
    }

    public final static Bitmap bilinearResample(Bitmap oriImg, int newWidth, int newHeight) {
        return bilinearResample(oriImg, newWidth, newHeight, WHITE);
    }

    /**
     * Function for scale an image from a large to a smaller size, then return a new image with new size predefined.
     */
    public final static Bitmap bilinearResample(Bitmap oriImg, int newWidth, int newHeight, int bgColor) {
        int oldW = oriImg.getWidth();
        int oldH = oriImg.getHeight();

        int[] ori_rgb = new int[oldW * oldH];
        int[] des_rgb = new int[newWidth * newHeight];

        oriImg.getPixels(ori_rgb, 0, oldW, 0, 0, oldW, oldH);

        int newIndex = 0;
        // draw each pixel in the new image
        for (int i = 1; i <= newHeight; i++) {
            // generate the y calculation variables
            int interplY = (i - 1) * oldH / newHeight;
            int calcY = (i - 1) * oldH % newHeight;

            for (int j = 1; j <= newWidth; j++) {
                // generate the x calculation variables
                int interplX = (j - 1) * oldW / newWidth;
                int calcX = (j - 1) * oldW % newWidth;

                int theColour1 = ori_rgb[(interplX) + (interplY) * oldW];
                int theColour2 = ori_rgb[(interplX + 1) + (interplY) * oldW];
                int theColour3 = ori_rgb[(interplX) + (interplY + 1) * oldW];
                int theColour4 = ori_rgb[(interplX + 1) + (interplY + 1) * oldW];

                // calculate the new colour
                int alpha1 = (theColour1 >> 24 & 0xFF) * (newHeight - calcY) / newHeight + (theColour3 >> 24 & 0xFF)
                        * calcY / newHeight;
                int alpha2 = (theColour2 >> 24 & 0xFF) * (newHeight - calcY) / newHeight + (theColour4 >> 24 & 0xFF)
                        * calcY / newHeight;
                int newAlpha = isOutofColor(alpha1 * (newWidth - calcX) / newWidth + alpha2 * calcX / newWidth);
                int newColor1r = (theColour1 >> 16 & 0xFF) * (newHeight - calcY) / newHeight
                        + (theColour3 >> 16 & 0xFF) * calcY / newHeight;
                int newColor2r = (theColour2 >> 16 & 0xFF) * (newHeight - calcY) / newHeight
                        + (theColour4 >> 16 & 0xFF) * calcY / newHeight;
                int newColorr = isOutofColor(newColor1r * (newWidth - calcX) / newWidth + newColor2r * calcX / newWidth);
                int newColor1g = (theColour1 >> 8 & 0xFF) * (newHeight - calcY) / newHeight + (theColour3 >> 8 & 0xFF)
                        * calcY / newHeight;
                int newColor2g = (theColour2 >> 8 & 0xFF) * (newHeight - calcY) / newHeight + (theColour4 >> 8 & 0xFF)
                        * calcY / newHeight;
                int newColorg = isOutofColor(newColor1g * (newWidth - calcX) / newWidth + newColor2g * calcX / newWidth);
                int newColor1b = (theColour1 & 0xFF) * (newHeight - calcY) / newHeight + (theColour3 & 0xFF) * calcY
                        / newHeight;
                int newColor2b = (theColour2 & 0xFF) * (newHeight - calcY) / newHeight + (theColour4 & 0xFF) * calcY
                        / newHeight;
                int newColorb = isOutofColor(newColor1b * (newWidth - calcX) / newWidth + newColor2b * calcX / newWidth);
                int newColor = ((newAlpha & 0xFF) << 24) | ((newColorr & 0xFF) << 16) | ((newColorg & 0xFF) << 8)
                        | (newColorb & 0xFF);

                // Set this pixel into the new image
                des_rgb[newIndex++] = newColor;
            }
        }

        Bitmap desImage = null;
        desImage = Bitmap.createBitmap(des_rgb, newWidth, newHeight, Bitmap.Config.RGB_565);
        // 缩放图片
        desImage = Bitmap.createScaledBitmap(desImage, newWidth, newHeight, true);
        if (desImage == null)
            desImage = oriImg;
        return desImage;
    }

    // it's used by the function bilinearResample().
    final static int isOutofColor(int color) {
        if (color < 0)
            color = 0;
        if (color > 255)
            color = 255;
        return color;
    }

    /**
     * If we are on low memory or the photo can not be loaded, we will show a red cross in the photo frame.
     */
    final static void createImageLoadFail(Canvas canvas) {
        Paint paint = new Paint();
        paint.setTypeface(Typeface.DEFAULT);
        int wh = (int) (4 * paint.getTextSize());
        canvas.drawRGB(0, 0, 0);
        canvas.drawRect(new Rect(0, 0, wh - 1, wh - 1), new Paint());
        canvas.drawRGB(255, 0, 0);
        int xStart = wh / 2 - 3;
        int yStart = wh / 2 - 3;

        canvas.drawLine(xStart, yStart, xStart + 6, yStart + 6, paint);
        canvas.drawLine(xStart, yStart + 1, xStart + 6, yStart + 7, paint);
        canvas.drawLine(xStart + 6, yStart, xStart, yStart + 6, paint);
        canvas.drawLine(xStart + 6, yStart + 1, xStart, yStart + 7, paint);
    }

    final static boolean isInComponent(int x, int y, View c) {
        if (c == null)
            return false;
        if (x < c.getLeft() || x > c.getLeft() + c.getWidth() || y < c.getTop() || y > c.getTop() + c.getHeight())
            return false;
        else
            return true;
    }
    
    /**
     * Divide the given string to paragraphs with the given font and width.
     * @param strSource
     *            the source string
     * @param font
     *            the font
     * @param width
     *            the width of each line.
     * @return the String array
     */
    public final static String[] getParagraph(final String strSource, final Paint font, final int width) {
        String[] strs = null;
        if (strSource == null || font == null || width <= 0) {
            return strs;
        } else if (strSource.equals("")) {
            strs = new String[] { "" };
            return strs;
        }
        Vector<String> vector = new Vector<String>();
        try {
            String temp = strSource;
            int i, j;
            boolean isOver;
            while (!temp.equals("")) {
                isOver = false; // 截取的一行文字是否超过width的标志，可以理解为自然段尾行的标志。
                i = temp.indexOf("\n");
                if (i == -1) { // 不含换行符的一大段文字。
                    i = temp.length();
                    isOver = font.measureText(temp) > width;
                }
                if (i > 0 && font.measureText(temp.substring(0, i)) > width) { // 含有换行符，超过width的一段文字。
                    isOver = true;
                }
                if (isOver) { // 行超过width，不是自然段尾行。
                    // gets the critical point
//                    while (font.measureText(temp.substring(0, i)) > width) {
//                        i = i - 1;
//                    }
                	i = font.breakText(temp.substring(0, i), true, width, null);
                	vector.addElement(temp.substring(0, i));
                } else { // 行不足width，已经达到自然段尾行。自然段尾行加入一个换行标志。
                	vector.addElement(temp.substring(0, i) + "\n");
                }
                if (i == temp.length()) {
                    temp = "";
                } else {
                    if (temp.charAt(i) == '\n') {
                        temp = temp.substring(i + 1);
                    } else {
                        temp = temp.substring(i);
                    }
                }
            }
            if (vector.size() > 0) {
                strs = new String[vector.size()];
                vector.copyInto(strs);
                vector.removeAllElements();
                vector.clear();
                vector = null;
            }
        } catch (Exception e) {

            printOutToConsole("getSubsection:" + e);
        }
        return strs;
    }

    /**
     * Divide the given string to paragraphs with the given font and width.
     * 
     * @param strSource
     *            the source string
     * @param font
     *            the font
     * @param width
     *            the width of each line.
     * @return the String array
     */
    public final static String[] getParagraph(final String strSource, final Paint font, final int width,
            final String splitChars) {
        String[] strs = null;
        if (strSource == null || font == null || width <= 0) {
            return strs;
        } else if (strSource.equals("")) {
            strs = new String[] { "" };
            return strs;
        }
        Vector vector = new Vector(2);
        try {
            String temp = strSource;
            int i, j;
            boolean isOver;
            while (!temp.equals("")) {
                isOver = false;
                i = temp.indexOf("\n");
                if (i == -1) {
                    i = temp.length();
                    isOver = font.measureText(temp) > width;
                }
                if (i > 0 && font.measureText(temp.substring(0, i)) > width) {
                    isOver = true;
                }
                if (isOver) {
                    // gets the critical point
//                    while (font.measureText(temp.substring(0, i)) > width) {
//                        i = i - 1;
//                    }
                	i = font.breakText(temp.substring(0, i), true, width, null);
                    if (!splitChars.equals("")) {
                        j = i; // restore the last index of this line for maybe
                        // there is a long word over a line.
                        while (splitChars.indexOf(temp.charAt(i - 1)) == -1) {
                            i--;
                            if (i == 0) {
                                i = j; // crash a word, if it is needed.
                                break;
                            }
                        }
                    }
                    vector.addElement(temp.substring(0, i));
                } else {
                	if (!splitChars.equals("")) {
                        j = i; // restore the last index of this line for maybe
                        // there is a long word over a line.
                        while (splitChars.indexOf(temp.charAt(i - 1)) == -1) {
                            i--;
                            if (i == 0) {
                                i = j; // crash a word, if it is needed.
                                break;
                            }
                        }
                    }
                    vector.addElement(temp.substring(0, i) + "\n");
                }
                if (i == temp.length()) {
                    temp = "";
                } else {
                    if (temp.charAt(i) == '\n') {
                        temp = temp.substring(i + 1);
                    } else {
                        temp = temp.substring(i);
                    }
                }
            }
            if (vector.size() > 0) {
                strs = new String[vector.size()];
                vector.copyInto(strs);
                vector.removeAllElements();
                vector.clear();
                vector = null;
            }
        } catch (Exception e) {

            printOutToConsole("getSubsection:" + e);
        }
        return strs;
    }

    /**
     * @param src
     *            source image.
     * @param desW
     *            expected width
     * @param desH
     *            expected height
     * @param isBackgroundTrans
     *            makes the background transparent
     * @param isTrans
     *            makes the image transparent
     * @return Image
     */
    // public final final static final Image scaleImage(Image src, int desW, int desH,
    // boolean isBackgroundTrans, boolean isTrans) {
    // Image desImg = null;
    // try {
    // int srcW = src.getWidth(); // source image width
    // int srcH = src.getHeight(); // source image height
    // int[] srcBuf = new int[srcW * srcH]; // source image pixel
    // src.getRGB(srcBuf, 0, srcW, 0, 0, srcW, srcH);
    // // compute interpolation table
    // int[] tabY = new int[desH];
    // int[] tabX = new int[desW];
    // int sb = 0;
    // int db = 0;
    // int tems = 0;
    // int temd = 0;
    // int distance = srcH > desH ? srcH : desH;
    // for (int i = 0; i <= distance; i++) { /* vertical direction */
    // tabY[db] = sb;
    // tems += srcH;
    // temd += desH;
    // if (tems > distance) {
    // tems -= distance;
    // sb++;
    // }
    // if (temd > distance) {
    // temd -= distance;
    // db++;
    // }
    // }
    // sb = 0;
    // db = 0;
    // tems = 0;
    // temd = 0;
    // distance = srcW > desW ? srcW : desW;
    // for (int i = 0; i <= distance; i++) { /* horizontal direction */
    // tabX[db] = (short) sb;
    // tems += srcW;
    // temd += desW;
    // if (tems > distance) {
    // tems -= distance;
    // sb++;
    // }
    // if (temd > distance) {
    // temd -= distance;
    // db++;
    // }
    // }
    // // formation enlarge and shorten buffer pixel
    // int[] desBuf = new int[desW * desH];
    // int dx = 0;
    // int dy = 0;
    // int sy = 0;
    // int oldy = -1;
    // for (int i = 0; i < desH; i++) {
    // if (oldy == tabY[i]) {
    // System.arraycopy(desBuf, dy - desW, desBuf, dy, desW);
    // } else {
    // dx = 0;
    // for (int j = 0; j < desW; j++) {
    // desBuf[dy + dx] = srcBuf[sy + tabX[j]];
    // dx++;
    // }
    // sy += (tabY[i] - oldy) * srcW;
    // }
    // oldy = tabY[i];
    // dy += desW;
    // }
    // if (isTrans) {
    // // int a= 100;//set the transparence of pixel 100
    // for (int i = 0; i < desBuf.length; i++) {
    // if (desBuf[i] == 0x00FFFFFF)
    // continue;
    // int alpha = ((desBuf[i] & 0xff000000) >>> 24) == 0 ? 0 : 100;
    // desBuf[i] = ((alpha + 1) << 24) | (desBuf[i] & 0x00FFFFFF);
    // }
    // }
    // if (isBackgroundTrans) {
    // desImg = Image.createRGBImage(desBuf, desW, desH, true);
    // } else {
    // desImg = Image.createRGBImage(desBuf, desW, desH, false);
    // }
    // } catch (Exception ex) {
    // LPUtils.printException(ex);
    // desImg = null;
    // }
    // return desImg;
    // }

    /**
     * @param strSrc
     * @param strSepr
     * @return
     */
    public final static String[] string2Array(String strSrc, String strSepr) {
        String[] astr = null;
        try {
            Vector vec = new Vector(5, 1);
            str2Arr(strSrc, strSepr, vec);
            vec.trimToSize();
            astr = new String[vec.size()];
            vec.copyInto(astr);
            vec.removeAllElements();
        } catch (Exception ex) {
        }
        return astr;
    }

    public final static void setPrint(Activity activity) {
        if (getConfigStringFormAsset(activity, "isprintMessage").equalsIgnoreCase("true")) {
            isPrintMessage_ = true;
        }
        setActivity(activity);
    }

    public final static void setActivity(Activity activity) {
        // TODO Auto-generated method stub
        activity_ = activity;
    }

    public final static Activity getActivity() {
        return activity_;
    }

    private final static void str2Arr(String strSrc, String strSepr, Vector vec) throws Exception {
        if (strSrc.indexOf(strSepr) == -1) {
            vec.addElement(strSrc);
        } else {
            vec.addElement(strSrc.substring(0, strSrc.indexOf(strSepr)));
            strSrc = strSrc.substring(strSrc.indexOf(strSepr) + strSepr.length());
            str2Arr(strSrc, strSepr, vec);
        }
    }

    // 将传入的字符串中的特�??��符予以替??�，�?�?解析顺利进行或使已替换的字符串还�?
    public final static String insteadOfSpecillCharacter(String str, boolean isReplace) {
        if ((null == str) || (str.equalsIgnoreCase("")))
            return str;
        String strTemp = str;
        // 特殊字符�?
        String[] A = { "&" };
        // 需要替换的字符
        String[] substitute;
        // 替换后的字符�?
        String[] B = { "***###" };
        // 替换后的字符
        String[] beReplaced;

        if (isReplace) {
            // 替换特殊字符�??��方便??��??
            substitute = A;
            beReplaced = B;
        } else {
            // 将特殊字符还�?
            substitute = B;
            beReplaced = A;
        }
        int length = substitute.length;
        for (int i = 0; i < length; i++) {
            strTemp = strTemp.replace(substitute[i], beReplaced[i]);
        }
        return strTemp;
    }

    /**
     * 控件联动
     * */
    public static void setCompontents() {
    	// TODO Auto-generated method stub
    	if(null != Component.VWIDGETARRAY){
    		int size = Component.VWIDGETARRAY.size();
    		for(int i = 0;i < size;i++ ){
    			Object o = Component.VWIDGETARRAY.get(i);
                if (o instanceof Component) {
                	if(((Component)o) instanceof LPSelect){
                		LPSelect lpsl = (LPSelect)o;
                		LPSelectOption option = null;
                		try{
                			option = (LPSelectOption) lpsl.childrenList_.get(lpsl.currentMenu());
                			//默认选择的option执行其onclick方法
                			//lpsl.setOnClick(option);
                		}catch(Exception e){
                			e.printStackTrace();
                		}
                		if(null != option){
                			lpsl.resetOtherSelectOptions(lpsl, option);
                		}
                	}else if (((Component)o) instanceof LPRadio){
                		if(LPToastUtil.getInstance().isBranchBank){
                			LPRadio lpr = (LPRadio)o;
                			String checked = lpr.getPropertyByName("checked");
                			if(null != checked && !"".equalsIgnoreCase(checked)){
                				lpr.setVisibleInvisible();
                			}
                			//默认选中LPRadio
                			/*if(!LPToastUtil.getInstance().isHasStyle){
                				if(null != lpr.radioList_ && lpr.radioList_.size()>0){
                					lpr.radioList_.get(0).setSelectedRadio();
                				}
                			}*/
                		}
                	}else if (((Component)o) instanceof LPCheckBox){
                		if(LPToastUtil.getInstance().isBranchBank){
                			LPCheckBox lpc = (LPCheckBox)o;
                			String checked = lpc.getPropertyByName("checked");
                			if(null != checked && !"".equalsIgnoreCase(checked)){
                				lpc.setVisibleInvisible(lpc.isChecked());
                			}                			
                		}
                	}
                }
    		}
    	}
    }
    
    /**
     * 设置控件的隐藏联动
     * @param visible
     * @param invisible
     */
    public static void setCompontentsLinked(String visible,String invisible){
    	if(null != visible && !"".equalsIgnoreCase(visible)){
    		String[] visibles = visible.split(",");
    		int size = visibles.length;
    		for(int i = 0 ;i < size;i++){
    			Component comp = getElementByName(visibles[i]);
    			if(null != comp){
    				comp.mouldCssStyleByName("display", "visible");    				
    			}
    		}
    	}
    	
    	if(null != invisible && !"".equalsIgnoreCase(invisible)){
    		String[] invisibles = invisible.split(",");
    		int size = invisibles.length;
    		for(int i = 0 ;i < size;i++){
    			Component comp = getElementByName(invisibles[i]);
    			if(null != comp){
    				comp.mouldCssStyleByName("display", "none");    				
    			}
    		}
    	}
    }
    
    /**
     * 获取控件通过名字
     * @param name
     * @return
     */
    public static Component getElementByName(String name){
    	if(null == name || "".equalsIgnoreCase(name) || null == Component.VWIDGETARRAY){
    		return null;
    	}
    	
        int size = Component.VWIDGETARRAY.size();
        Object o = null;
        Component view;
        String tagName;
        for (int i = 0; i < size; i++) {
            o = Component.VWIDGETARRAY.get(i);
            if (o instanceof Component) {
                view = (Component) o;
                tagName = (String) view.property_.get("name");
                if (null != tagName) {
                    if (name.equals(tagName))
                        return (Component)o;
                }
            }
        }
        return null;
    }
    // 设置与是否获得焦�?
    // final final static public void setFocus(boolean isFocus, int keyCode, View view) {
    // if (view instanceof LPTable) {
    // LPTable temp = (LPTable) view;
    // // temp.setFocus(isFocus, keyCode);
    // } else {
    // if (isFocus) {
    // view.requestFocus();
    // } else {
    // view.clearFocus();
    // }
    // }
    //
    // }

    /**
     * @param obj
     */
    public final static void printOutToConsole(Object obj) {
        if (isPrintMessage_) {
            if (obj instanceof String) {
                printOutToConsole((String) obj);
            } else if (obj instanceof byte[]) {
                printOutToConsole((byte[]) obj);
            } else {
                System.out.println(obj);
            }
        }
    }

    /**
     * @param s
     */
    public final static void printOutToConsole(String s) {
        if (isPrintMessage_) {
            int length = s.length();
            int offset = 3000;
            if (length > offset) {// 解决报文过长，打印不全的问题�?
                int n = 0;
                for (int i = 0; i < length; i += offset) {
                    n += offset;
                    if (n > length)
                        n = length;
                    System.out.println(s.substring(i, n));
                }
            } else {
                System.out.println(s);
            }
        }
    }

    /**
     * @param byts
     */
    public final static void printOutToConsole(byte[] byts) {
        if (isPrintMessage_) {
            if (byts == null) {
                return;
            }
            for (int i = 0; i < byts.length; i++) {
                System.out.print("[" + i + "]" + " : \t");
                System.out.println(byts[i]);
            }
        }
    }

    public final static void LogD(String tag, String msg) {
        if (isPrintMessage_) {
            android.util.Log.d(tag, msg);
        }
    }

    public final static void printException(Exception e) {
        if (isPrintMessage_) {
            e.printStackTrace();
        }
    }

    /**
     * 检?��服务端发过来的接口前面是否带�?,如果没有则自动加�提高程序健壮�
     * 
     * @param url
     * @return
     */
    public final static String checkUrl(Object url) {
        // TODO Auto-generated method stub
        String tempString = url.toString().trim();
        if (!tempString.startsWith("/"))
            tempString = "/".concat(tempString);
        return tempString;
    }

    /**
     * Network Byte Order
     * 
     * @param byts
     * @param offset
     * @return
     */
    public final static int byteArrayToIntInNBO(byte[] byts, int offset) {
        int intValue = 0;
        for (int i = 0; i < 4; i++) {
            int shift = (4 - 1 - i) * 8;
            intValue += (byts[i + offset] & 0x000000FF) << shift;
        }
        return intValue;
    }

    /**
     * Network Byte Order
     * 
     * @param intValue
     * @return
     */
    public final static byte[] intToByteArrayInNBO(int intValue) {
        byte[] byt = new byte[4];
        for (int i = 0; i < 4; i++) {
            byt[i] = (byte) (intValue >>> (24 - i * 8));
        }
        return byt;
    }

    /**
     * @param firstBytes
     * @param lastBytes
     * @return
     */
    public final static byte[] jogBytes(byte[]... byts) throws Exception {
        if (byts.length == 0) {
            return null;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        for (byte[] byt : byts) {
            if (byt == null) {
                continue;
            }
            out.write(byt);
        }
        try {
            out.flush();
        } catch (Exception e) {
            printException(e);
        }
        byte[] result = out.toByteArray();
        try {
            out.close();
        } catch (Exception e) {
            printException(e);
        }
        out = null;
        return result;
    }

    public final static String getStringFormAsset(Activity activity, String str) {
        BufferedReader in = null;
        try {
            in = new BufferedReader(new InputStreamReader(activity.getAssets().open(str)), 8 * 1024);
            String line;
            StringBuilder buffer = new StringBuilder();
            while ((line = in.readLine()) != null)
                buffer.append(line).append('\n');
            return buffer.toString();
        } catch (IOException e) {
            Utils.printException(e);
            return "";
        } finally {
            if (in != null) {
                try {
                    in.close();
                    in = null;
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    printException(e);
                }
            }
        }
    }


	/**
	 * 得到当天日期
	 * @return
	 */
	public static String getNowDate() {
		Calendar c = Calendar.getInstance();
		c.setTimeZone(TimeZone.getTimeZone("GMT+8"));
		String yearStr;
		String monthStr;
		String dayStr;
		yearStr = c.get(Calendar.YEAR) + "";
		// 月份从0算起，所以应该+1处理
		monthStr = c.get(Calendar.MONTH) + 1 + "";
		if (((c.get(Calendar.MONTH) + 1) < 10) && (monthStr.length() < 2)) {
			monthStr = "0".concat(monthStr);
		}
		dayStr = c.get(Calendar.DAY_OF_MONTH) + "";
		if (dayStr.length() < 2) {
			dayStr = "0".concat(dayStr);
		}
		String dateStr = yearStr.concat(monthStr).concat(dayStr);
		return dateStr;
	}
	
    /**
     * 修正日期值的传输，将�”予以去除，月份日期小于10，则前面予以�?
     * 
     * @param value
     * @return
     */
    public final static String adjustDate(String value) {
        // TODO Auto-generated method stub
        if (value.contains("-")) {
            String valueTemp = value;
            String year = valueTemp.substring(0, valueTemp.indexOf("-"));
            String month = valueTemp.substring(valueTemp.indexOf("-") + 1, valueTemp.lastIndexOf("-"));
            String day = valueTemp.substring(valueTemp.lastIndexOf("-") + 1);
            if (Integer.parseInt(month) < 10 && month.length() < 2)
                month = "0".concat(month);
            if (Integer.parseInt(day) < 10 && day.length() < 2)
                day = "0".concat(day);
            return year.concat(month).concat(day).replace("-", "");
        }
        return value;
    }

    /**
     * 解读assets文件夹下的Config.txt文件信息
     * 
     * @param activity
     * @param tag
     *            需要在该文件里面查找的key
     * @return 文件中key对应的value
     */
    public final static String getConfigStringFormAsset(Activity activity, String tag) {
    	if(activity == null){
    		activity = activity_;
    	}
        if (configHm_ == null) {
            initConfigStringFormAsset(activity);
        }
        String value = configHm_.get(tag);
        return value == null ? "" : value;
    }

    /**
     * 解读assets文件夹下的Config.txt文件信息，现在改为本地存储这些数值。
     * 
     * @param activity
     * @param tag
     *            需要在该文件里面查找的key
     * @return 文件中key对应的value
     */
    private final static void initConfigStringFormAsset(Activity activity) {
        // 　只读取一次Config文件
        if (null == activity)
            return;
        configHm_ = new HashMap<String, String>();
        /**
         * 在本地添加这些数值。
         */
        // 联网地址。
        configHm_.put("SERVER_URI", Utils.SERVER_URI);
        configHm_.put("SERVER_URI_NO_PORT", Utils.SERVER_URI_NO_PORT);
        // session密钥。
        configHm_.put("SESSION_KEY", "phone/get_keys?");
        // 基础比较分辨率宽高,该数值必须与服务端模板参考的像素值一致。
        configHm_.put("BenchmarkresolutionW", "320");
        configHm_.put("BenchmarkresolutionH", "480");
        // 两次点击的最大有效间隔时间(毫秒),用于判定用户点击是否是连击。
        configHm_.put("jat_lag", "300");
        // 离线存储平台。
        configHm_.put("offstoreplatform", "android");
        // 是否开启打印日志标记。
        configHm_.put("isprintMessage", "false");
        // 联网获取图片的接口。
        configHm_.put("GET_PIC_URI", "/map/get_pic?");
        // 项目名称参数，用于每次联网请求.
        configHm_.put("app", "ebank");
        // 后台定的平台代码,基本上每次联网都需要传给后台,靠此标记选择报文。
        configHm_.put("oPlatform", "i");
        // 请求handshake接口时所传参数ota_version中的客户端类型。
        configHm_.put("clientType", "AD");
        // 加密信道双向验证标记。
        configHm_.put("two-way_authentication", "false");
        // 加密机密钥。
        configHm_.put("hsmclikey", "F979C6609E5EDF0FE148CDD1A44EC94F2068993FB477206CA4F8AE4EEDED1EA77E2E0BEE9EA27C17E5F55B9559BF3CFC5265E0A41243816E8185A6CD93391A0ADB013732941EEA3D4D90F559EF1958696FCEE30232690A7448DD9F665FDA974EBA0510CA19FD8C9525497CCB3A0FDD045B546D13FF87B075279C3725F3038CB9");
        configHm_.put("hsmcliEXPONENT", "65537"); 
        // 由于网络引发的问题普通用户看不懂，所以用这条来代替。
        configHm_.put("httpError", "通信异常，请检查您的网络设置及通讯情况!"); 
        // br节点高度值配置，该值是相对于320X480屏幕指定，会参与不同屏幕尺寸的缩放操作。
        configHm_.put("brHeight", "10");
        // body框架纵向边距。
        configHm_.put("verticalMarginOfB", "0");
        // body框架水平边距。
        configHm_.put("horizontalMarginOfB", "0");
        // body框架子元素纵向间距。
        configHm_.put("verticalGapOfB", "0");
        // body框架子元素横向间距。
        configHm_.put("horizontalGapOfB", "0");
        // form框架纵向边距。
        configHm_.put("verticalMarginOfF", "5");
        // form框架水平边距。
        configHm_.put("horizontalMarginOfF", "5");
        // form框架子元素纵向间距。
        configHm_.put("verticalGapOfF", "5");
        // form框架子元素横向间距。
        configHm_.put("horizontalGapOfF", "5");
        // div框架纵向边距。
        configHm_.put("verticalMarginOfD", "0");
        // div框架水平边距。
        configHm_.put("horizontalMarginOfD", "0");
        // div框架子元素纵向间距。
        configHm_.put("verticalGapOfD", "5");
        // div框架子元素横向间距。
        configHm_.put("horizontalGapOfD", "5");
        // td框架纵向边距。
        configHm_.put("verticalMarginOfT", "4");
        // td框架水平边距。
        configHm_.put("horizontalMarginOfT", "4");
        // td框架子元素纵向间距。
        configHm_.put("verticalGapOfT", "4");
        // td框架子元素横向间距。
        configHm_.put("horizontalGapOfT", "4");
        // 默认字体颜色  (可支持红黑白黄灰等多种颜色)。
        configHm_.put("textColor", "black");
        // 是否使用push功能。
        configHm_.put("usePush", "false");
        // 一字一密接口。
        configHm_.put("dynamickey", "/user_s/dynamickey?");
        configHm_.put("cominternal", "com.android.internal.R$dimen");
        configHm_.put("statusbarheight", "status_bar_height");
        // Lua脚本库最高版本。
//        configHm_.put("LuaMaxVersion", "RYTL_1.0.9.lua");
        
        jat_lag = Integer.parseInt(configHm_.get("jat_lag"));
    }

    public final static int getScaledValueX(float num) {
        // TODO Auto-generated method stub
        float numtemp = SCALEDATEX * num;
        return (int) numtemp;
    }

    public final static int getFontSize(int size) {
        size = (int) (size * SCALEDFONT);
        return size;
    }

    public final static int getScaledValueY(float num) {
        // TODO Auto-generated method stub
        float numtemp = SCALEDATEY * num;
        return (int) numtemp;
    }

    /**
     * 
     * @param wRate
     *            参照宽度
     * @param hRate
     */
    private final static void setScaledParams(float wRate, float hRate) {
        // TODO Auto-generated method stub
        SCALEDATEX = wRate;
        SCALEDATEY = hRate;
    }

    // 计算界面宽高
    public final static void calculateScreenSize(Activity activity) {
    	//用来关闭软键盘的工具类
    	immUtils = new InputMethodUtil();
    	
        // 从Config配置文档中读取服务端xml的基准分辨率，该分辨率应时刻与服务端定义的模板标准分辨率一�?
        BenchmarkresolutionW_ = Integer.parseInt(getConfigStringFormAsset(activity, "BenchmarkresolutionW"));
        BenchmarkresolutionH_ = Integer.parseInt(getConfigStringFormAsset(activity, "BenchmarkresolutionH"));

        DisplayMetrics dm = new DisplayMetrics();
        activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
        Component.SCREENWIDTH = dm.widthPixels;
        // 该值为暂定值无实际意义，该值会在BaseView的onWindowFocusChanged方法中从新计算得�?
        // Component.SCREENHEIGHT = dm.heightPixels;
        final float w = BenchmarkresolutionW_;
        final float h = BenchmarkresolutionH_;
        float wRate = dm.widthPixels / w;
        float hRate = dm.heightPixels / h;
        setScaledParams(wRate, hRate);
        setBrHeight();
        setMarginAndGap();
        SCALEDFONT = 1;
        int dw = dm.widthPixels;
        int dh = dm.heightPixels;
        float ds = dm.scaledDensity;
        
//        if (dw <= 240 && dh <= 320) {
//            if (ds != 0.75f) {
//                SCALEDFONT = 0.75f / ds;
//            }
//        } else if (dw <= 320 && dh <= 500) {
//            if (ds != 1f) {
//                SCALEDFONT = 1f / ds;
//            }
//        } else if (dw <= 480 && dh <= 900) {
//            if (ds != 1.5f) {
//                SCALEDFONT = 1.5f / ds;
//            }
//        } else if (dw <= 600) {
//            if (ds != 2f) {
//                SCALEDFONT = 2f / ds;
//            }
//        }
        
        // 计算文字的缩放比例。
        SCALEDFONT = dw / 320.0f;
    }

    private static void setMarginAndGap() {
        // TODO Auto-generated method stub
        String tempString = getConfigStringFormAsset(getActivity(), "verticalMarginOfB");
        if (null == tempString || tempString.equals(""))
            tempString = "0";
        LPLayout.VMB = getScaledValueY(Integer.parseInt(tempString));
        printOutToConsole("Config设置的body框架纵向边距经过缩放后为:" + LPLayout.VMB);

        tempString = getConfigStringFormAsset(getActivity(), "horizontalMarginOfB");
        if (null == tempString || tempString.equals(""))
            tempString = "0";
        LPLayout.HMB = getScaledValueX(Integer.parseInt(tempString));
        printOutToConsole("Config设置body框架水平边距经过缩放后为:" + LPLayout.HMB);

        tempString = getConfigStringFormAsset(getActivity(), "verticalGapOfB");
        if (null == tempString || tempString.equals(""))
            tempString = "0";
        LPLayout.VGB = getScaledValueY(Integer.parseInt(tempString));
        printOutToConsole("Config设置的body框架子元素纵向间距经过缩放后为：" + LPLayout.VGB);

        tempString = getConfigStringFormAsset(getActivity(), "horizontalGapOfB");
        if (null == tempString || tempString.equals(""))
            tempString = "0";
        LPLayout.HGB = getScaledValueX(Integer.parseInt(tempString));
        printOutToConsole("Config设置的body框架子元素横向间距经过缩放后为：" + LPLayout.HGB);

        tempString = getConfigStringFormAsset(getActivity(), "verticalMarginOfF");
        if (null == tempString || tempString.equals(""))
            tempString = "0";
        LPLayout.VMF = getScaledValueY(Integer.parseInt(tempString));
        printOutToConsole("Config设置的form框架纵向边距经过缩放后为:" + LPLayout.VMF);

        tempString = getConfigStringFormAsset(getActivity(), "horizontalMarginOfF");
        if (null == tempString || tempString.equals(""))
            tempString = "0";
        LPLayout.HMF = getScaledValueX(Integer.parseInt(tempString));
        printOutToConsole("Config设置的form框架水平边距经过缩放后为:" + LPLayout.HMF);

        tempString = getConfigStringFormAsset(getActivity(), "verticalGapOfF");
        if (null == tempString || tempString.equals(""))
            tempString = "0";
        LPLayout.VGF = getScaledValueY(Integer.parseInt(tempString));
        printOutToConsole("Config设置的form框架子元素纵向间距经过缩放后为：" + LPLayout.VGF);

        tempString = getConfigStringFormAsset(getActivity(), "horizontalGapOfF");
        if (null == tempString || tempString.equals(""))
            tempString = "0";
        LPLayout.HGF = getScaledValueX(Integer.parseInt(tempString));
        printOutToConsole("Config设置的form框架子元素横向间距经过缩放后为：" + LPLayout.HGF);

        tempString = getConfigStringFormAsset(getActivity(), "verticalMarginOfD");
        if (null == tempString || tempString.equals(""))
            tempString = "0";
        LPLayout.VMD = getScaledValueY(Integer.parseInt(tempString));
        printOutToConsole("Config设置的div框架纵向边距经过缩放后为：" + LPLayout.VMD);

        tempString = getConfigStringFormAsset(getActivity(), "horizontalMarginOfD");
        if (null == tempString || tempString.equals(""))
            tempString = "0";
        LPLayout.HMD = getScaledValueX(Integer.parseInt(tempString));
        printOutToConsole("Config设置的div框架水平边距经过缩放后为:" + LPLayout.HMD);

        tempString = getConfigStringFormAsset(getActivity(), "verticalGapOfD");
        if (null == tempString || tempString.equals(""))
            tempString = "0";
        LPLayout.VGD = getScaledValueY(Integer.parseInt(tempString));
        printOutToConsole("Config设置的div框架子元素纵向间距经过缩放后为：" + LPLayout.VGD);

        tempString = getConfigStringFormAsset(getActivity(), "horizontalGapOfD");
        if (null == tempString || tempString.equals(""))
            tempString = "0";
        LPLayout.HGD = getScaledValueX(Integer.parseInt(tempString));
        printOutToConsole("Config设置的div框架子元素横向间距经过缩放后为：" + LPLayout.HGD);

        tempString = getConfigStringFormAsset(getActivity(), "verticalMarginOfT");
        if (null == tempString || tempString.equals(""))
            tempString = "0";
        LPLayout.VMT = getScaledValueY(Integer.parseInt(tempString));
        printOutToConsole("Config设置的td框架纵向边距经过缩放后为:" + LPLayout.VMT);

        tempString = getConfigStringFormAsset(getActivity(), "horizontalMarginOfT");
        if (null == tempString || tempString.equals(""))
            tempString = "0";
        LPLayout.HMT = getScaledValueX(Integer.parseInt(tempString));
        printOutToConsole("Config设置的td框架水平边距经过缩放后为:" + LPLayout.HMT);

        tempString = getConfigStringFormAsset(getActivity(), "verticalGapOfT");
        if (null == tempString || tempString.equals(""))
            tempString = "0";
        LPLayout.VGT = getScaledValueY(Integer.parseInt(tempString));
        printOutToConsole("Config设置的td框架子元素纵向间距经过缩放后为：" + LPLayout.VGT);

        tempString = getConfigStringFormAsset(getActivity(), "horizontalGapOfT");
        if (null == tempString || tempString.equals(""))
            tempString = "0";
        LPLayout.HGT = getScaledValueX(Integer.parseInt(tempString));
        printOutToConsole("Config设置的td框架子元素横向间距经过缩放后为:" + LPLayout.HGT);
    }

    public static void setBrHeight() {
        // TODO Auto-generated method stub
        String tempString = getConfigStringFormAsset(getActivity(), "brHeight");
        if (null == tempString || tempString.equals(""))
            tempString = "0";
        BRHEIGHT = getScaledValueY(Integer.parseInt(tempString));
        printOutToConsole("Config设置的br节点高度经过缩放后为:" + BRHEIGHT);
    }

    public static int getBrHeight() {
        return BRHEIGHT;
    }

    /**
     * 获取手机的model型号
     * 
     * @return
     */
    public final static String getPhoneModel() {
        String temp = android.os.Build.MODEL;
        temp = temp.replace(" ", "").replace("-", "_").trim();
        return temp;
    }

    public final static String getPhoneTarget() {
        String temp = android.os.Build.DEVICE;
        temp = temp.replace(" ", "").replace("-", "_").trim();
        return temp;

    }

    public final static String getClientID() {
        String temp = android.os.Build.ID;
        temp = temp.replace(" ", "").replace("-", "_").trim();
        return temp;
    }

    /**
     * 获取界面分辨率并且组合成�?
     * 
     * @param activity
     * @return
     */
    public final static String getResolution(Activity activity) {
        DisplayMetrics dm = new DisplayMetrics();
        activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
        String w = String.valueOf(dm.widthPixels);
        String h = String.valueOf(dm.heightPixels);
        return w.concat("*").concat(h);
    }

    public final static Typeface getTypeFace(String string) {
        Typeface tface = null;
        try {
            if (string.equalsIgnoreCase("bold")) {
                tface = Typeface.defaultFromStyle(Typeface.BOLD);
            } else if (string.equalsIgnoreCase("normal")) {
                tface = Typeface.defaultFromStyle(Typeface.NORMAL);
            } else {
                tface = null;
            }
        } catch (Exception e) {
            tface = null;
        }
        return tface;
    }

    /**
     * 设置字体是否粗体
     * */
    private final static boolean getFontType(String string) {
        if (string.equalsIgnoreCase("bold")) {
            return true;
        } else {
            return false;
        }
    }

    /** * 图片去色,返回灰度图片 * @param bmpOriginal 传入的图�? @return 去色后的图片 */
    public final static Bitmap getGrayBitmap(Bitmap bmpOriginal) {
        if (null == bmpOriginal)
            return null;
        int width, height;
        height = bmpOriginal.getHeight();
        width = bmpOriginal.getWidth();
        Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(bmpGrayscale);
        Paint paint = new Paint();
        ColorMatrix cm = new ColorMatrix();
        cm.setSaturation(0);
        ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
        paint.setColorFilter(f);
        c.drawBitmap(bmpOriginal, 0, 0, paint);
        return bmpGrayscale;
    }

    /**
     * @param activity
     * @param fileName
     * @param data
     */
    public final static void updateFile(Activity activity, String fileName, byte[] data) {
        try {
            FileOutputStream fos = activity.openFileOutput(fileName, Activity.MODE_PRIVATE);
            fos.write(new byte[] {}); // clear file.
            fos.write(data);
            fos.flush();
            fos.close();
        } catch (FileNotFoundException e) {
            Utils.printException(e);
        } catch (IOException e) {
            Utils.printException(e);
        } catch (Exception e) {
            Utils.printException(e);
        }

    }

    /**
     * @param activity
     * @param fullPathName
     * @return
     */
    public final static byte[] readFile(String fullPathName) {
        byte[] buffer = null;
        FileInputStream fis = null;
        try {
            File file = new File(fullPathName);
            if (file.exists()) {
                fis = new FileInputStream(file);
                int len = fis.available();
                buffer = new byte[len];
                fis.read(buffer);
                if(!Utils.getMIMEType(file).equals("image")){
                    buffer = AESCipher.decrypt(buffer, AESCipher.customerKey_, AESCipher.customerIv_);
                }
            }
        } catch (FileNotFoundException e) {
            printException(e);
        } catch (IOException e) {
            printException(e);
        } catch (Exception e) {
            printException(e);
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                }
            }
        }
        return buffer;
    }

    public final static String getVersionName(Activity activity) {
        try {
            PackageManager pm = activity.getPackageManager();

            PackageInfo pi;

            pi = pm.getPackageInfo(activity.getPackageName(), PackageManager.GET_ACTIVITIES);
            return pi.versionName;
        } catch (NameNotFoundException e) {
            // TODO Auto-generated catch block
            Utils.printException(e);
            return "1.0";
        }

    }

    /**
     * User-Agent string we use in all of our HTTP transactions. XXX DO NOTE CHANGE THIS!!
     */
    public final static String makeUserAgent(String version) {
        StringBuffer buf = new StringBuffer("LightPole/");
        buf.append(version);
        buf.append("/");
        buf.append("android1.5");
        return buf.toString();
    }

    // Get a code from data.
    private final static int getCode(byte data[], int tree[]) {
        int node = tree[0];
        while (node >= 0) {
            if (bitIndex == 0)
                bitByte = (data[gIndex++] & 0xFF);
            node = (((bitByte & (1 << bitIndex)) == 0) ? tree[node >> 16] : tree[node & 0xFFFF]);
            bitIndex = (bitIndex + 1) & 0x7;
        }
        return (node & 0xFFFF);
    }

    /**
     * 判断报文是否存在xml�如果没有则手动加�
     * 
     * @param xml
     * @return
     */
    public final static String addXmlHead(String xml) {
        if (xml.indexOf("<?xml") == -1) {
            xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>".concat(xml);
        }
        return xml;
    }

    // get num bits from data. the num should not bigger than 32.
    private final static int getBits(byte[] data, int num) {
        int result = 0;
        int i = 0;
        if (bitIndex != 0) {
            i = 8 - bitIndex;
            result = bitByte >> bitIndex;
        }
        while (i < num) {
            bitByte = data[gIndex++] & 0xFF;
            result |= (bitByte << i);
            i += 8;
        }
        bitIndex = (bitIndex + num) & 0x7;// calculate (bitIndex + num)%8
        result &= (0xffffffff >>> (32 - num));
        return result;
    }

    // It's used to decompress gzip data. Re. rfc1951 and rfc 1952.
    public final static byte[] gunzip(byte[] gzipData) throws IOException {
        // Check if the data is gzip format and if it is used "deflate"
        // compression method.
        if (gzipData[0] != 31 || gzipData[1] != -117)
            throw new IOException("压缩数据格式错误!");
        if (gzipData[2] != 8)
            throw new IOException("压缩数据方法错误!");

        // Skip the gzip data header.
        byte flg = gzipData[3];
        gIndex = 10;
        bitIndex = 0;
        bitByte = 0;
        if ((flg & 4) != 0)
            gIndex += getBits(gzipData, 16);
        if ((flg & 8) != 0)
            while (gzipData[gIndex++] != 0)
                ;
        if ((flg & 16) != 0)
            while (gzipData[gIndex++] != 0)
                ;
        if ((flg & 2) != 0)
            gIndex += 2;

        int temp = gIndex;
        gIndex = gzipData.length - 4;
        // The size of the original input data
        int size = getBits(gzipData, 16) | (getBits(gzipData, 16) << 16);
        byte[] unzipData = new byte[size];
        gIndex = temp;

        int unzipIndex = 0;
        bitIndex = 0;
        bitByte = 0;
        int lastBlock = 0; // 0 indicates have more block when 1 indicates it is
        // the last block.
        int type = 0;// 0 indicates uncompress data, 1 indicates use final final static
        // Huffman, 2 indicates use dynamic Huffman.
        while (lastBlock == 0) {
            lastBlock = getBits(gzipData, 1);
            type = getBits(gzipData, 2);
            if (type == 0) {
                // uncompress data
                bitIndex = 0;
                int length = getBits(gzipData, 16);
                gIndex += 2;
                System.arraycopy(gzipData, gIndex, unzipData, unzipIndex, length);
                gIndex += length;
                unzipIndex += length;
            } else {
                byte[] lBits;
                byte[] dBits;
                if (type == 1) {
                    // use final final static huffman.
                    lBits = new byte[288];// The lTree node numbers 286, the
                    // last two nodes is use for full
                    // tree.
                    for (int i = 0; i < 288; i++) {
                        if (i < 144 || i > 279) {
                            lBits[i] = 8;
                        } else if (i < 256) {
                            lBits[i] = 9;
                        } else {
                            lBits[i] = 7;
                        }
                    }
                    dBits = new byte[32];// The dTree node numbers 30, the last
                    // two nodes is use for full tree.
                    for (int i = 0; i < dBits.length; i++) {
                        dBits[i] = 5;
                    }
                } else if (type == 2) {
                    // use dynamic huffman.
                    int hlit = getBits(gzipData, 5) + 257;
                    int hdist = getBits(gzipData, 5) + 1;
                    int hclen = getBits(gzipData, 4) + 4;
                    byte[] bltreeBits = new byte[19];// The blTree node numbers
                    // 19.
                    for (int i = 0; i < hclen; i++)
                        bltreeBits[DYNAMIC_L_ORDER[i]] = (byte) getBits(gzipData, 3);
                    int[] blTree = huffmanTree(bltreeBits);
                    lBits = decompressCode(gzipData, blTree, hlit);
                    dBits = decompressCode(gzipData, blTree, hdist);
                } else {
                    throw new IOException("不能正确解压数据.");
                }

                int[] lTree = huffmanTree(lBits);// The literal/length tree.
                int[] dTree = huffmanTree(dBits);// The distance tree.
                int code = 0;
                while ((code = getCode(gzipData, lTree)) != 256) {// code=256
                    // indicates
                    // the end
                    // of this
                    // block.
                    if (code < 256) {// literal byte
                        unzipData[unzipIndex++] = (byte) code;
                    } else {// length/distance pairs
                        code -= 257;
                        int length = EXTRA_L_VALUES[code];
                        if (EXTRA_L_BITS[code] > 0)
                            length += getBits(gzipData, EXTRA_L_BITS[code]);
                        code = getCode(gzipData, dTree);
                        int distance = EXTRA_D_VALUES[code];
                        if (EXTRA_D_BITS[code] > 0)
                            distance += getBits(gzipData, EXTRA_D_BITS[code]);
                        while (distance < length) {
                            System.arraycopy(unzipData, unzipIndex - distance, unzipData, unzipIndex, distance);
                            unzipIndex += distance;
                            length -= distance;
                        }
                        System.arraycopy(unzipData, unzipIndex - distance, unzipData, unzipIndex, length);
                        unzipIndex += length;
                    }
                }
            }
        }
        return unzipData;
    }

    // Get a huffman tree.
    private final static int[] huffmanTree(byte bits[]) {
        int bl_count[] = new int[MAX_BITS + 1];
        for (int i = 0; i < bits.length; i++) {
            bl_count[bits[i]]++;
        }
        int code = 0;
        bl_count[0] = 0;
        int next_code[] = new int[MAX_BITS + 1];
        // Count the number of codes for each code length.
        for (int i = 1; i <= MAX_BITS; i++) {
            code = (code + bl_count[i - 1]) << 1;
            next_code[i] = code;
        }
        int tree[] = new int[((bits.length - 1) << 1) + MAX_BITS];
        int treeInsert = 1;
        for (int i = 0; i < bits.length; i++) {
            int len = bits[i];
            if (len != 0) {
                code = next_code[len]++;
                int node = 0;
                for (int bit = len - 1; bit >= 0; bit--) {
                    int value = code & (1 << bit);
                    if (value == 0) {
                        int left = tree[node] >> 16;
                        if (left == 0) {
                            tree[node] |= (treeInsert << 16);
                            node = treeInsert++;
                        } else
                            node = left;
                    } else {
                        int right = tree[node] & 0xFFFF;
                        if (right == 0) {
                            tree[node] |= treeInsert;
                            node = treeInsert++;
                        } else
                            node = right;
                    }
                }
                tree[node] = 0x80000000 | i;
            }
        }
        return tree;
    }

    // Decompress the literal/length code and the distance code.
    private final static byte[] decompressCode(byte data[], int blTree[], int count) {
        int code = 0;
        byte previousCode = 0;
        int times = 0; // The number of the previous code's length need to
        // repeat.
        byte treeBits[] = new byte[count];
        int index = 0;
        while (index < count) {
            code = getCode(data, blTree);
            if (code == 16) {
                times = getBits(data, 2) + 3;
            } else if (code == 17) {
                times = getBits(data, 3) + 3;
                previousCode = 0;
            } else if (code == 18) {
                times = getBits(data, 7) + 11;
                previousCode = 0;
            } else {
                times = 0;
                previousCode = (byte) code;
                treeBits[index++] = (byte) code;
            }
            for (int i = 0; i < times; i++) {
                treeBits[index++] = previousCode;
            }
        }
        return treeBits;
    }

    public final static String getVersion() {
        // 获取手机操作系统版本�?
        return android.os.Build.VERSION.RELEASE;
    }

    public final static String getModel() {
        // 获取手机型号
        return android.os.Build.MODEL;
    }

    public final static String getName() {
    	// 手机机主名称，没有则返回nil
    	String user = android.os.Build.USER;
    	if(user == null || user.equalsIgnoreCase("unknown")){
    	    user = "";
    	}
    	return user;
    }

    public final static String getDeviceName() {
        return android.os.Build.DEVICE;
    }

    public final static String getPlayform() {
        // 当前系统平台
        return "Android";
    }

    public final static String getUUID() {
        final TelephonyManager tm = (TelephonyManager) activity_.getBaseContext().getSystemService(
                Context.TELEPHONY_SERVICE);
        final String tmDevice, tmSerial, tmPhone, androidId;
        tmDevice = "" + tm.getDeviceId();
        tmSerial = "" + tm.getSimSerialNumber();
        androidId = ""
                + android.provider.Settings.Secure.getString(activity_.getContentResolver(),
                        android.provider.Settings.Secure.ANDROID_ID);
        UUID deviceUuid = new UUID(androidId.hashCode(), ((long) tmDevice.hashCode() << 32) | tmSerial.hashCode());
        return deviceUuid.toString();
    }

    public final static String connectType(Activity bv) {
        // TODO Auto-generated method stub
        try {
            Context context = bv.getApplicationContext();
            ConnectivityManager connectivity = (ConnectivityManager) context
                    .getSystemService(Context.CONNECTIVITY_SERVICE);

            NetworkInfo ni = connectivity.getActiveNetworkInfo();

            if ((null != ni) && ni.isAvailable()) {
                return ni.getTypeName();
            }
        } catch (Exception e) {
            Utils.printException(e);
            return getConfigStringFormAsset(getActivity(), "httpError");
        }
        return getConfigStringFormAsset(getActivity(), "httpError");

    }

    private final static String getLocationByNet(Activity bv) {
        // TODO Auto-generated method stub
        double LATITUDE = 0;
        double LONGITUDE = 0;
        int timeoutConnection = 3000;
        int timeoutSocket = 5000;
        TelephonyManager mTelNet = (TelephonyManager) bv.getSystemService(Context.TELEPHONY_SERVICE);
        String operator = mTelNet.getNetworkOperator();
        CellLocation cl = mTelNet.getCellLocation();
        // #ifdef Android2.2
        if (cl instanceof CdmaCellLocation) {
            CdmaCellLocation location = (CdmaCellLocation) cl;
            LATITUDE = (double) location.getBaseStationLatitude() / 14400;// 14400�?90/1296000
            LONGITUDE = (double) location.getBaseStationLongitude() / 14400;

        } else if (null != operator && !operator.equals("")) {
            // #else
            // @ if (null != operator && !operator.equals("")) {
            // #endif
            String mcc = operator.substring(0, 3);
            String mnc = operator.substring(3);

            if (cl instanceof GsmCellLocation) {
                GsmCellLocation location = (GsmCellLocation) cl;
                if (null != location) {
                    int cid = location.getCid();
                    int lac = location.getLac();
                    HttpParams httpParameters = new BasicHttpParams();
                    HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
                    HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
                    HttpClient httpclient = new DefaultHttpClient(httpParameters);
                    HttpPost post = new HttpPost("http://www.google.com/loc/json");
                    try {
                        JSONObject holder = new JSONObject();
                        holder.put("version", "1.1.0");
                        holder.put("host", "maps.google.com");
                        holder.put("address_language", "zh_CN");
                        holder.put("request_address", true);
                        JSONObject tower = new JSONObject();
                        tower.put("mobile_country_code", mcc);
                        tower.put("mobile_network_code", mnc);
                        tower.put("cell_id", cid);
                        tower.put("location_area_code", lac);
                        JSONArray towerarray = new JSONArray();
                        towerarray.put(tower);
                        holder.put("cell_towers", towerarray);
                        StringEntity query = new StringEntity(holder.toString());
                        post.setEntity(query);
                        HttpResponse response = httpclient.execute(post);
                        HttpEntity entity = response.getEntity();
                        BufferedReader buffReader = new BufferedReader(new InputStreamReader(entity.getContent()));
                        StringBuffer strBuff = new StringBuffer();
                        String result = null;
                        while ((result = buffReader.readLine()) != null) {
                            strBuff.append(result);
                        }
                        JSONObject json = new JSONObject(strBuff.toString());
                        JSONObject subjosn = new JSONObject(json.getString("location"));
                        LATITUDE = Double.parseDouble(subjosn.getString("latitude"));
                        LONGITUDE = Double.parseDouble(subjosn.getString("longitude"));
                    } catch (Exception e) {
                        // LPUtils.printException(e);
                        Utils.printException(e);
                    }
                }
            }
        }

        return (String.valueOf(LATITUDE)).concat(",").concat(String.valueOf(LONGITUDE));
    }

    /**
     * 查看android手机是否被刷过机.linux系统下root权限可以使用su命令，android本身也是小型的linux系统
     * 
     * @param command
     *            "id" 或其他的 su命令
     */
    public final static boolean runRootCommand(String command) {

        Process process = null;
        DataOutputStream os = null;
        try {
            process = Runtime.getRuntime().exec("su");
            os = new DataOutputStream(process.getOutputStream());
            os.writeBytes(command + "\n");
            os.writeBytes("exit\n");
            os.flush();
            process.waitFor();
        } catch (Exception e) {
            printException(e);
            return false;
        } finally {
            try {
                if (os != null) {
                    os.close();
                }
                process.destroy();
            } catch (Exception e) {
                // nothing
            }
        }
        return true;
    }

    public static void saveFile(String name, byte[] buffer) {
        if (null == name || name.equals(""))
            return;
        name = OffStoreDownload.FILEROOT.concat(name);

        if (name.endsWith("/")) {
            // 数据以／结尾（例：ｓｙｇｈ／ｃｓｓ／），表示是路径，此时应建立文件夹
            createPath(name);
        } else {
            createFile(name, buffer);
        }
    }

    /**
     * 保存图片到本地
     * @param filePath
     * @param fileName
     * @param bitmap
     */
    public static void saveBitmap(String filePath,String fileName,Bitmap bitmap){
		File file = new File(filePath);
		if (!file.exists()) {
			file.mkdir();
		}
		File imageFile = new File(file, fileName+".png");
		try {
			imageFile.createNewFile();
			FileOutputStream fos = new FileOutputStream(imageFile);
			bitmap.compress(CompressFormat.PNG, 100, fos);
			fos.flush();
			fos.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
    }
    
    private static void createFile(String path, byte[] buffer) {
        // TODO Auto-generated method stub
        File file = null;
        FileOutputStream fstream = null;
        try {
            file = new File(path);
            //判断父目录是否存在
            if (!file.exists()) {
                File vDirPath = file.getParentFile();
                vDirPath.mkdirs();
            }
            file.createNewFile();
            fstream = new FileOutputStream(file);
            if(!Utils.getMIMEType(file).equals("image")){
                buffer = AESCipher.encrypt(buffer, AESCipher.customerKey_, AESCipher.customerIv_);
            }
            fstream.write(buffer);
        } catch (Exception e) {
            printException(e);
        } finally {

            if (fstream != null) {

                try {
                    fstream.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    printException(e);
                }

            }

        }
    }

    /**
     * * 保存对象到文�? * @param obj * @param fileName * @throws Exception
     * 
     * @param publicKey
     */
    public static void saveFile(Activity activity, Object obj, String fileName) {
        ObjectOutputStream output;
        try {
            output = new ObjectOutputStream(activity.openFileOutput(fileName, Context.MODE_PRIVATE));

            output.writeObject(obj);
            output.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            printException(e);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            printException(e);
        }
    }

	/**
	 * 读取Config的文本默认颜色设置，如果没有，默认为黑色
	 * 
	 * @param activity
	 */
	public static void readTextClolr(Activity activity) {
		String colortemp = getConfigStringFormAsset(activity, "textColor");
		Component.TEXTCOLOR = Color.BLACK;
		if (null != colortemp && !colortemp.equals("")) {
			if (colortemp.equalsIgnoreCase("black"))
				Component.TEXTCOLOR = Color.BLACK;
			else if (colortemp.equalsIgnoreCase("BLUE"))
				Component.TEXTCOLOR = Color.BLUE;
			else if (colortemp.equalsIgnoreCase("CYAN"))
				Component.TEXTCOLOR = Color.CYAN;
			else if (colortemp.equalsIgnoreCase("dkgray"))
				Component.TEXTCOLOR = Color.DKGRAY;
			else if (colortemp.equalsIgnoreCase("white"))
				Component.TEXTCOLOR = Color.WHITE;
			else if (colortemp.equalsIgnoreCase("gray"))
				Component.TEXTCOLOR = Color.GRAY;
			else if (colortemp.equalsIgnoreCase("green"))
				Component.TEXTCOLOR = Color.GREEN;
			else if (colortemp.equalsIgnoreCase("ltgray"))
				Component.TEXTCOLOR = Color.LTGRAY;
			else if (colortemp.equalsIgnoreCase("magenta"))
				Component.TEXTCOLOR = Color.MAGENTA;
			else if (colortemp.equalsIgnoreCase("red"))
				Component.TEXTCOLOR = Color.RED;
			else if (colortemp.equalsIgnoreCase("transparent"))
				Component.TEXTCOLOR = Color.TRANSPARENT;
			else if (colortemp.equalsIgnoreCase("yellow"))
				Component.TEXTCOLOR = Color.YELLOW;
		}
	}

	/** * 从文件读取object * * @param fileName * @return * @throws Exception */
	public static Object readFromFile(Activity activity, String fileName) {
		ObjectInputStream input;
		try {
			input = new ObjectInputStream(activity.openFileInput(fileName));
			Object obj = input.readObject();
			input.close();
			return obj;
		} catch (StreamCorruptedException e) {
			// TODO Auto-generated catch block
			printException(e);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			printException(e);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			printException(e);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			printException(e);
		}
		return null;
	}

	public static void createPath(String path) {
		File file = new File(path);
		if (!file.exists()) {
			file.mkdirs();
		}
	}

	/**
	 * 初始化本地存储的 key,iv
	 * 
	 * @param activity
	 */
	public static void initCustomerSecretKey(Activity activity) {
		try {
			TelephonyManager tm = (TelephonyManager) activity.getSystemService(Activity.TELEPHONY_SERVICE);
			String deviceId = tm.getDeviceId();
			String deviceName = Build.DEVICE;
			String packageName = activity.getPackageName();
			if (deviceId == null) {
				deviceId = "";
			}
			if (deviceName == null) {
				deviceName = "";
			}
			if (packageName == null) {
				packageName = "com.rytong.tools";
			}
			String message = deviceId.concat(deviceName).concat(packageName)
					.concat(RSACipher.PUBLIC_CER_MODULUS_FILENAME).concat(HMac.KEY_MAC_MD5);
			byte[] sha1 = HMac.SHA1(message.getBytes());
			byte[] md5 = MD5.getMD5(message.getBytes());
			byte[] secretKey = new byte[sha1.length + md5.length];
			System.arraycopy(sha1, 0, secretKey, 0, sha1.length);
			System.arraycopy(md5, 0, secretKey, sha1.length, md5.length);
			AESCipher.customerKey_ = ClientHello.getAESKey(secretKey);
			AESCipher.customerIv_ = new byte[16];
			for (int i = 0; i < 16; i++) {
				AESCipher.customerIv_[i] = secretKey[secretKey.length - 1 - i];
			}
		} catch (Exception e) {
			printOutToConsole(e);
		}
	}

	/**
	 * 删除空目录
	 * */
	public static void deleteEmptyPath(File targetF){
		if(!targetF.exists() || targetF.isFile()){
			return ;
		}

		File[] files = targetF.listFiles();
		for(File tempF : files){
			if(tempF.isDirectory()){
				if(tempF.list().length == 0){
					tempF.delete();
				} else {
					deleteEmptyPath(tempF);

					if(tempF.list().length == 0){
						tempF.delete();
					}
				}
			}
		}
	}

	public static String getFilePath(File file , String fileName){
		String filePath = null;
		if(file == null || TextUtils.isEmpty(fileName)){
			return null;
		}
		if(file.isDirectory()){
			File[] files = file.listFiles();
			for(File tempFile : files){
				filePath = getFilePath(tempFile,fileName);
				if(filePath != null){
					break;
				}
			}
		} else {
			if(file.getName().equalsIgnoreCase(fileName)){
				filePath = file.getParent();
				return filePath;
			}
		}
		return filePath;
	} 

	/**
	 * 取出字符串中第一组数字
	 * 如：abcd0.6667saf58af;取出为float f = 0.6667;
	 * @param str
	 * @return
	 */
	public static float getDigital(String str) {

        String cache = "";
        for (int i = 0; i < str.length(); i++) {

            if (str.charAt(i) == 46 || (str.charAt(i) >= 48 && str.charAt(i) <= 57)) {

                cache += str.charAt(i);
            } else if (cache.length() > 0) {

                break;
            }
        }
        return Float.valueOf(cache);
    }

    
    /**
     * 
     * */
    public static Map<String,Integer> getMatrixIndex(){
        Map<String,Integer> map = new HashMap<String, Integer>();
        map.put("m11", 0);
        map.put("m12", 3);
        map.put("m13", 6);
        map.put("m21", 1);
        map.put("m22", 4);
        map.put("m23", 7);
        map.put("m31", 2);
        map.put("m32", 5);
        map.put("m33", 8);
        return map;
    }
    
    /**
     * 
     * */
    public static HashMap getTableValue(LuaObject table){

		HashMap resultMap = new HashMap();

		table.push();
		Component.LUASTATE.pushNil();
		String keyString = "";
		String valueString = "";
		while (Component.LUASTATE.next(-2) != 0) {
			keyString = "";
			if (Component.LUASTATE.type(-2) == Component.LUASTATE.LUA_TNUMBER) {
				keyString = Double.toString(Component.LUASTATE.toNumber(-2));
			} else if (Component.LUASTATE.type(-2) == Component.LUASTATE.LUA_TSTRING) {
				keyString = Component.LUASTATE.toString(-2);
			}

			valueString = "";
			if (Component.LUASTATE.type(-1) == Component.LUASTATE.LUA_TTABLE) {
				try {
					Object t = Component.LUASTATE.toJavaObject(-1);
					LuaObject luaTable = (LuaObject)t;
					HashMap map = getInnerTableValue(luaTable);
					resultMap.put(keyString, map);
				} catch (Exception e) {
					e.printStackTrace();
				}
			} else {
				if (Component.LUASTATE.type(-1) == Component.LUASTATE.LUA_TNUMBER) {
					valueString = Double.toString(Component.LUASTATE.toNumber(-1));
				} else if (Component.LUASTATE.type(-1) == Component.LUASTATE.LUA_TSTRING) {
					valueString = Component.LUASTATE.toString(-1);
				} 
				resultMap.put(keyString, valueString);
			}

			Component.LUASTATE.pop(1);
		}
		Component.LUASTATE.pop(2);
		return resultMap;
	}

	/**
	 * 
	 * */
	public static HashMap getInnerTableValue(LuaObject table){

		HashMap resultMap = new HashMap();
		try{
			table.push();
			// 循环读取table中的属性值
			Component.LUASTATE.pushNil();
			String keyString = "";
			String valueString = "";
			while (Component.LUASTATE.next(-2) != 0) {
				keyString = "";
				if (Component.LUASTATE.type(-2) == Component.LUASTATE.LUA_TNUMBER) {
					keyString = Double.toString(Component.LUASTATE.toNumber(-2));
				} else if (Component.LUASTATE.type(-2) == Component.LUASTATE.LUA_TSTRING) {
					keyString = Component.LUASTATE.toString(-2);
				}
				valueString = "";
				if (Component.LUASTATE.type(-1) == Component.LUASTATE.LUA_TNUMBER) {
					valueString = Double.toString(Component.LUASTATE.toNumber(-1));
				} else if (Component.LUASTATE.type(-1) == Component.LUASTATE.LUA_TSTRING) {
					valueString = Component.LUASTATE.toString(-1);
				} else if (Component.LUASTATE.type(-1) == Component.LUASTATE.LUA_TTABLE) {
				}

				resultMap.put(keyString, valueString);
				Component.LUASTATE.pop(1);
			}
			Component.LUASTATE.pop(1);
		}catch(Exception e){
			Utils.printException(e);
		}
		return resultMap;
	}

	/**
	 * 读取资源文件 (返回byte[])
	 * 先加载本地的资源文件， 如果本地不存在则请求服务器
	 * @param src
	 * @return
	 */
	public static byte[] readResFile(String src){
		byte[] buffer = null;
		if(!TextUtils.isEmpty(src)){
			//从本地资源文件加载
			buffer = readLocalFile(src);
			if(buffer == null || buffer.length == 0){
				//本地找不到时，从服务器下载
				buffer = readServerFile(src); 
			}
		}
		return buffer;
	}

	/**
	 * 从服务器获取资源，返回byte[]
	 * @param src
	 * @return
	 */
	public static byte[] readServerFile(String src){
		byte[] buffer = null;

		if(!TextUtils.isEmpty(src)){
			try{
				String resInter = Utils.getConfigStringFormAsset(activity_, "GET_RESFILE_URI");
				String uri = Utils.getConfigStringFormAsset(activity_, "SERVER_URI").concat(resInter);
				if(!src.startsWith("/")){
					src = "/" + src;
				}
				String platform = Utils.getConfigStringFormAsset(activity_, "offstoreplatform");
				String screenResolution = getResolution(activity_);

				StringBuffer sb = new StringBuffer();
				sb.append("name=channels").append(src).append("&");
				sb.append("platform=").append(platform).append("&");
				sb.append("resolution=").append(screenResolution);
				String body = sb.toString();
				Utils.printOutToConsole("downloadFileFromServer()uri------" + uri);
				Utils.printOutToConsole("downloadFileFromServer()body------" + body);
				body = AESCipher.encrypt(body, AESCipher.clientKey_, AESCipher.clientIv_);

				String reply = "";
				HttpManager hm = new HttpManager(activity_);
				Object obj = hm.sendPostRequest(uri, body, null, null);
				if(obj instanceof byte[]){
					reply = new String((byte[]) obj , "UTF-8");
				}
				reply = AESCipher.decrypt(reply, AESCipher.serverKey_, AESCipher.serverIv_);
				reply = Utils.unescapeHTML(reply);
				reply = Utils.insteadOfSpecillCharacter(reply, true);
				//<?xml version='1.0' encoding='utf-8'?> <error string="invalid file path"/>
				if(reply.indexOf("<error") != -1){
					//返回错误信息
					reply = "";
				}
				if(!TextUtils.isEmpty(reply)){
					buffer = reply.getBytes();
				}
			}catch(Exception e){
				Utils.printException(e);
			}
		}

		return buffer;
	}

	/**
	 * 读取本地文件返回字符串
	 * @param fileName
	 * @return
	 */
	public static String readLocalFileForStr(String fileName){
		String content = "";

		byte[] buffer = readLocalFile(fileName);

		try {
			if(buffer != null){
				content = new String(buffer, "UTF-8");
			}
		} catch (UnsupportedEncodingException e) {
			Utils.printException(e);
		}
		return content;
	}

	/**
	 * 加载本地文件;读取文件的优先级顺序为：插件资源 > 离线下载资源 > file：write写出的资源 > 安装包资源。
	 * 
	 * @param fileName
	 */
	public static byte[] readLocalFile(String fileName) {
		byte[] buffer = null;
		if (TextUtils.isEmpty(fileName)) {
			return buffer;
		}
		FileInputStream fis = null;
		try {
			//           // 插件资源
			//           buffer = Utils.readFile(OffStoreDownload.FILEROOT.concat(OffStoreDownload.PLUGROOT).concat(fileName));
			// 插件资源,调用时带有路径
			Object object = OffStoreDB.PLUGDB.find(fileName);
			if (object != null && object instanceof byte[]) {
				// 服务器哈希值
				String serveRev = new String(AESCipher.decrypt((byte[]) object, AESCipher.customerKey_,
						AESCipher.customerIv_));
				// 读取文件
				buffer = Utils.readFile(OffStoreDownload.FILEROOT.concat(OffStoreDownload.PLUGROOT).concat(fileName));
				// 计算文件SHA1值
				if (buffer != null) {
					String shaFile = getSHA1(buffer);
					if (shaFile == null || !shaFile.equalsIgnoreCase(serveRev)) {
						// 如果文件被篡改 ,则需要删除文件并重新请求离线资源下载（待完成...）
						buffer = null;
					}
				}

			}

			// 离线下载资源 ， 直接使用文件名字调用
			if (null == buffer) {
				//               // 离线下载资源
				//               buffer = Utils
				//                       .readFile(OffStoreDownload.FILEROOT.concat(OffStoreDownload.OFFLINEROOT).concat(fileName));
				object = OffStoreDB.OFFLINEDB.find(fileName);
				if (object != null && object instanceof byte[]) {
					// 服务器哈希值
					String serveRev = new String(AESCipher.decrypt((byte[]) object, AESCipher.customerKey_,
							AESCipher.customerIv_));
					// 读取文件
					buffer = Utils.readFile(OffStoreDownload.FILEROOT.concat(OffStoreDownload.OFFLINEROOT).concat(fileName));
					// 计算文件SHA1值
					if (buffer != null) {
						String shaFile = getSHA1(buffer);
						if (shaFile == null || !shaFile.equalsIgnoreCase(serveRev)) {
							// 如果文件被篡改 ,则需要删除文件并重新请求离线资源下载（待完成...）
							buffer = null;
						}
					}
				}

			}
			if (null == buffer) {
				// file：write写出的资源
				buffer = Utils.readFile(OffStoreDownload.FILEROOT.concat(OffStoreDownload.WRITEROOT).concat(fileName));
			}
			//           if (null != buffer && buffer.length > 0) {
			//               result = new String(buffer, "UTF-8");
			//           } else {
			//               // 安装包资源
			//               result = Utils.getStringFormAsset(activity_, fileName);
			if (null == buffer && activity_ != null) {
				File tempFile = new File(fileName);
				String filePath = "";
				if (Utils.getMIMEType(tempFile).equalsIgnoreCase("image")) {
					filePath = "images/";
				} else if (Utils.getMIMEType(tempFile).equalsIgnoreCase("audio")) {
					filePath = "audios/";
				} else if (Utils.getMIMEType(tempFile).equalsIgnoreCase("video")) {
					filePath = "videos/";
				}
				String content = Utils.getStringFormAsset(activity_, filePath + fileName);
				if (!content.equals("")) {
					buffer = content.getBytes();
				}
			}
		} catch (Exception e) {
			Utils.printException(e);
		} finally {
			if (fis != null) {
				try {
					fis.close();
					fis = null;
				} catch (IOException e) {
					Utils.printException(e);
				}
			}
		}

		return buffer;
	}

	/**
	 * 获取SHA1值  离线资源存储、读取时会用到
	 * @param buffer
	 * @return
	 */
	public static String getSHA1(byte[] buffer){
		String serveRev = null;
		if(buffer != null){
			byte[] temp = HMac.SHA1(buffer);
			serveRev = HMac.byteArrayToHexString(temp);
		}
		return serveRev;
	}

	/**
	 * 获取日期对应的星期几。
	 * 
	 * @param activity 当前的activity。
	 * @param cal 日历对象。
	 * @return 星期几的字符串。
	 */
	public static String getDayOfWeek(Activity activity, Calendar cal) {
		if (cal == null) {
			return null;
		}
		String dayOfWeekStr = null;
		int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
		switch (dayOfWeek) {
		case Calendar.SUNDAY:
			dayOfWeekStr = activity.getResources().getString(R.string.sunday);
			break;
		case Calendar.MONDAY:
			dayOfWeekStr = activity.getResources().getString(R.string.monday);
			break;
		case Calendar.TUESDAY:
			dayOfWeekStr = activity.getResources().getString(R.string.tuesday);
			break;
		case Calendar.WEDNESDAY:
			dayOfWeekStr = activity.getResources().getString(R.string.wednesday);
			break;
		case Calendar.THURSDAY:
			dayOfWeekStr = activity.getResources().getString(R.string.thursday);
			break;
		case Calendar.FRIDAY:
			dayOfWeekStr = activity.getResources().getString(R.string.friday);
			break;
		case Calendar.SATURDAY:
			dayOfWeekStr = activity.getResources().getString(R.string.saturday);
			break;
		default:
			break;
		}
		return dayOfWeekStr;
	}

	/**
	 * 给定一个控件，寻找其所在tr的方法。
	 * 
	 * @param source 需要进行查找的组件。
	 * @return source组件所在的tr。
	 */
	public static Component getTR(Component source){
		while(!(source != null && source.getTag() != null && "tr".equals(source.getTag())
				&& source.getPropertyByName("onclick") != null
				&& !"".equals(source.getPropertyByName("onclick")))){
			if(source == null){
				break;
			}
			source = source.getParent();
		}
		return source;
	}

	/**
	 * 
	 * @param src
	 * @param com
	 */
	public static void downloadImageFromRemoteByPostAsyn(final String src , final Component com) {
		if (!TextUtils.isEmpty(src) && com != null) {
			WaitDialog wd = new WaitDialog();
			wd.addBgTask(new Task(0) {
				@Override
				public void run(WaitDialog dlg) throws Exception {
					// TODO Auto-generated method stub

					//本地无法获取再从服务器获取
					byte[] imageBytes = readServerFile(src);
					if(imageBytes != null){
						if (com != null) {
							Bitmap bmp = Utils.getBitmap(imageBytes);
							if(bmp != null){
								saveFile(OffStoreDownload.WRITEROOT.concat(src), imageBytes);
								com.unFocusImg_ = bmp;
								activity_.runOnUiThread(new Runnable(){
									@Override
									public void run() {
										// TODO Auto-generated method stub
										com.setBackgroundDrawable(new BitmapDrawable(com.unFocusImg_));
										com.postInvalidate();
									}

								});
							} 
						}
					}
				}
			});
		}
	}

	/**
	 * 判断SDCard是否存在
	 * @return
	 */
	public static boolean isSDCardExists(){
		return Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
	}

	/**
	 * 获取SDCard路径
	 * @return
	 */
	public static String getSDCardRoot(){
		String root = "";
		if(isSDCardExists()){
			root = Environment.getExternalStorageDirectory().toString() + "/";
		}
		return root;
	}

	/**
	 * 获取本地资源文件路径  (主要使用对象   视频音频文件)
	 * (插件资源 > 离线下载资源 > file：write写出的资源 = > return (String) path ;  安装包资源  = > return AssetFile)
	 * @param fileName
	 * @return
	 */
	public static Object getLocalFilePath(String fileName) {
		String path = "";
		AssetFileDescriptor afDescriptor = null;
		if (TextUtils.isEmpty(fileName)) {
			return null;
		}
		byte[] buffer = null;
		FileInputStream fis = null;
		try {
			// 插件资源,调用时带有路径
			Object object = OffStoreDB.PLUGDB.find(fileName);
			if (object != null && object instanceof byte[]) {
				// 服务器哈希值
				String serveRev = new String((byte[]) object);
				// 读取文件
				buffer = Utils.readFile(OffStoreDownload.FILEROOT.concat(OffStoreDownload.PLUGROOT).concat(fileName));
				// 计算文件SHA1值
				if (buffer != null) {
					String shaFile = getSHA1(buffer);
					if (shaFile == null || !shaFile.equalsIgnoreCase(serveRev)) {
						// 如果文件被篡改 ,则需要删除文件并重新请求离线资源下载（待完成...）
						buffer = null;
					} else {
						path = OffStoreDownload.FILEROOT.concat(OffStoreDownload.PLUGROOT).concat(fileName);
					}
				}
			}
			// 离线下载资源 ， 直接使用文件名字调用
			if (null == buffer) {
				object = OffStoreDB.OFFLINEDB.find(fileName);
				if (object != null && object instanceof byte[]) {
					// 服务器哈希值
					String serveRev = new String((byte[]) object);
					// 读取文件
					buffer = Utils.readFile(OffStoreDownload.FILEROOT.concat(OffStoreDownload.OFFLINEROOT).concat(fileName));
					// 计算文件SHA1值
					if (buffer != null) {
						String shaFile = getSHA1(buffer);
						if (shaFile == null || !shaFile.equalsIgnoreCase(serveRev)) {
							// 如果文件被篡改 ,则需要删除文件并重新请求离线资源下载（待完成...）
							buffer = null;
						} else {
							path = OffStoreDownload.FILEROOT.concat(OffStoreDownload.OFFLINEROOT).concat(fileName);
						}
					}
				}
			}

			if (null == buffer) {
				// file：write写出的资源
				buffer = Utils.readFile(OffStoreDownload.FILEROOT.concat(OffStoreDownload.WRITEROOT).concat(fileName));
				if(buffer != null){
					path = OffStoreDownload.FILEROOT.concat(OffStoreDownload.WRITEROOT).concat(fileName);
				}
			}
			if(!TextUtils.isEmpty(path)){
				//表示在 插件 、 离线、写出资源中已找到
				return path;
			} else {
				//否则 查找安装包下资源
				if (null == buffer && activity_ != null) {
					File tempFile = new File(fileName);
					String filePath = "";
					if (Utils.getMIMEType(tempFile).equalsIgnoreCase("image")) {
						filePath = "images/";
					} else if (Utils.getMIMEType(tempFile).equalsIgnoreCase("audio")) {
						filePath = "audios/";
					} else if (Utils.getMIMEType(tempFile).equalsIgnoreCase("video")) {
						filePath = "videos/";
					}

					String[] list = activity_.getAssets().list(filePath.substring(0, filePath.length() - 1));
					for (int i = 0; i < list.length; i++) {
						String tempStr = list[i];
						if (tempStr.equals(fileName)) {
							afDescriptor = activity_.getAssets().openFd(filePath + fileName);
							return afDescriptor;
						}
					}
				}
			}
		} catch (Exception e) {
			Utils.printException(e);
		} finally {
			if (fis != null) {
				try {
					fis.close();
					fis = null;
				} catch (IOException e) {
					Utils.printException(e);
				}
			}
		}
		return null;
	}


	/**
	 * 下载并保存文件至file.write 路径下
	 * 
	 * @param url  下载地址
	 * @param name 文件名
	 * @return  文件存储路径
	 */
	public static String downloadAndSaveFile(String url , String name){

		String path = "";
		if(!TextUtils.isEmpty(url) && !TextUtils.isEmpty(name)){
			path = OffStoreDownload.FILEROOT.concat(OffStoreDownload.WRITEROOT).concat(name);// 存储路径

			ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
			byte[] buffer = null;
			try {
				HttpManager hm = new HttpManager(activity_);
				hm.read(url, out, null);
				buffer = out.toByteArray();
				saveFile(path, buffer);
			} catch (Exception e) {
				path = "";
				Utils.printException(e);
			} catch (OutOfMemoryError oe) {
				path = "";
				Utils.printOutToConsole(oe);
			} finally {
				if (null != out)
					try {
						out.close();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						path = "";
						Utils.printException(e);
					}
				out = null;
			}
		}
		return path;
	}

	/**
	 * 释放当前ImageView里的图片，以释放内存
	 * @param imageView
	 */
	public static void releaseObject(Object object){
		if(null == object)
			return;
		if(object instanceof ImageView){
			ImageView imageView = (ImageView)object;
			final ImageView finalIv = imageView;
			getActivity().runOnUiThread(new Runnable() {

				@Override
				public void run() {
					finalIv.setBackgroundDrawable(null);
				}
			});
			if(null != imageView ){
				if(null != imageView.getDrawable()){
					Bitmap oldBitmap = ((BitmapDrawable)imageView.getDrawable()).getBitmap();
					releaseObject(oldBitmap);
				}
				imageView = null;
			}
		} else if(object instanceof View){
			View view = (View)object;
			if(view != null && view.getDrawingCache() != null){
				Bitmap oldBitmap = view.getDrawingCache();
				releaseObject(oldBitmap);
			}
			view = null;
		} else if(object instanceof Bitmap){
			Bitmap oldBitmap = (Bitmap)object;
			if(null != oldBitmap && !oldBitmap.isRecycled()){
				oldBitmap.recycle();
			}
			oldBitmap = null;
		}else{
			object = null;
		}
	}
	
	/**
	 * 记录密码键盘抬起时，输入框的上移的距离
	 */
	public static int height_;
	
	/**
	 *  弹出自定义密码键盘
	 * @param bv
	 * @param edit 输入框
	 * @param dlg  弹出的dialog
	 * @param main 需要滚动的视图
	 */
	public static void showInputWindow(final BaseView bv, final EditText edit,final Object main){
		LPKeyBoard mKeyBoard = new LPKeyBoard(bv ,edit);
		if(null == keyDlg_){
			int animation = Utils.getResourcesId(bv, "popupAnimation1", "style");
			keyDlg_ = new Dialog(bv,animation);
			//点击dialog以外的区域关闭dialog
			keyDlg_.setCanceledOnTouchOutside(true);
			// 设置dialog位置
			Window mWindow = keyDlg_.getWindow();
			mWindow.setWindowAnimations(animation);
			mWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
			// 使对话框位于屏幕的底部并居中
			mWindow.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
			// 使对话框二边没有空隙
			mWindow.setLayout(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
			
			//弹出对话框后去除变暗阴影
			WindowManager.LayoutParams lp = mWindow.getAttributes();
			lp.dimAmount = 0f;
			mWindow.setAttributes(lp);
		}

		mKeyBoard.getInstance();
		keyDlg_.setContentView(mKeyBoard.mRootView,new LayoutParams(Component.SCREENWIDTH, LayoutParams.WRAP_CONTENT));

		if (!keyDlg_.isShowing()){
			keyDlg_.show();
			mKeyBoard.mDialog = keyDlg_;
			int[] location = new int[2];
			//输入框在屏幕中的位置x,y
			edit.getLocationInWindow(location);
			//输入框底部与屏幕底部的距离
			int bottomY = Component.SCREENHEIGHT -location[1] - 2*edit.getHeight() + 55;
			if(bottomY <= mKeyBoard.getHeight()){
				//需要向上滚动的距离
				int temp = Math.abs(mKeyBoard.getHeight()-bottomY);
				setViewBottomHeight(bv,main, temp);
			}
			keyDlg_.setOnDismissListener(new OnDismissListener(){
				@Override
				public void onDismiss(DialogInterface dialog) {
					//关闭键盘时将原先滚动的距离还原
					setViewBottomHeight(bv,main,-height_);
					height_= 0;
					//				if(edit.isFocused()){
					//					edit.clearFocus();
					//				}
				}
			});
		}
	}
	
	/**
	 * 检测本机中是否已安装应用
	 * @param context
	 * @param packageName
	 * @return
	 */
	public static boolean isInstalled(Activity context,String packageName){
		boolean isInstalled = false;
		if(null != packageName && !"".equalsIgnoreCase(packageName)){
			PackageManager pm = context.getPackageManager();
			List<PackageInfo> pkgs = pm.getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);
			for(PackageInfo pkg	:pkgs){
				//包名
				if(packageName.equalsIgnoreCase(pkg.packageName)){
					isInstalled  = true;
				}
			}
		}
		return isInstalled;
	}
	
	/**
	 * 滚动main视图，使得输入框始终在密码键盘上面
	 * @param main
	 * @param height
	 */
	public static void setViewBottomHeight(BaseView bv,final Object main, final int height){
		try{
			bv.runOnUiThread(new Runnable(){

				@Override
				public void run() {
					if(null != main){
						height_ = height;
						if(main instanceof LPScrollView){
							LPScrollView lpsc = (LPScrollView)main;
							((MyLPLayout)((LPLayout)lpsc.getParent()).realView_).scrollBy(0, height);
						}else if(main instanceof LinearLayout){
							LinearLayout lly = (LinearLayout)main;
							lly.scrollBy(0, height);
						}
					}
				}
			});
		}catch(Exception e){
			e.printStackTrace();
		}
	}
}
